[repository] Initial population of WinAoE into git repository
authorShao Miller <Shao.Miller@yrdsb.edu.on.ca>
Mon, 29 Jun 2009 22:48:21 +0000 (18:48 -0400)
committerShao Miller <Shao.Miller@yrdsb.edu.on.ca>
Mon, 29 Jun 2009 22:48:21 +0000 (18:48 -0400)
Build environment: MSYS (MingW)
Git environment:   Cygwin

47 files changed:
Makefile [new file with mode: 0644]
changelog.txt [new file with mode: 0644]
config.bat [new file with mode: 0644]
gpl.txt [new file with mode: 0644]
makechecked.bat [new file with mode: 0644]
makedist.bat [new file with mode: 0644]
makedriver.bat [new file with mode: 0644]
makefree.bat [new file with mode: 0644]
makeinf.bat [new file with mode: 0644]
makeutils.bat [new file with mode: 0644]
readme.txt [new file with mode: 0644]
src/aoe.c [new file with mode: 0644]
src/aoe.h [new file with mode: 0644]
src/bus.c [new file with mode: 0644]
src/debug.c [new file with mode: 0644]
src/disk.c [new file with mode: 0644]
src/driver.c [new file with mode: 0644]
src/driver.h [new file with mode: 0644]
src/loader.c [new file with mode: 0644]
src/mount.c [new file with mode: 0644]
src/mount.h [new file with mode: 0644]
src/portable.h [new file with mode: 0644]
src/protocol.c [new file with mode: 0644]
src/protocol.h [new file with mode: 0644]
src/pxe.asm/Makefile [new file with mode: 0644]
src/pxe.asm/aoe.S [new file with mode: 0644]
src/pxe.asm/aoe.h [new file with mode: 0644]
src/pxe.asm/aoe.ld [new file with mode: 0644]
src/pxe.asm/debug.S [new file with mode: 0644]
src/pxe.asm/global.S [new file with mode: 0644]
src/pxe.asm/int13.S [new file with mode: 0644]
src/pxe.asm/lib.S [new file with mode: 0644]
src/pxe.asm/pxe.S [new file with mode: 0644]
src/pxe.c/Makefile [new file with mode: 0644]
src/pxe.c/aoe.ld [new file with mode: 0644]
src/pxe.c/asm.S [new file with mode: 0644]
src/pxe.c/asm.h [new file with mode: 0644]
src/pxe.c/debug.S [new file with mode: 0644]
src/pxe.c/lib.c [new file with mode: 0644]
src/pxe.c/lib.h [new file with mode: 0644]
src/pxe.c/libasm.S [new file with mode: 0644]
src/pxe.c/main.c [new file with mode: 0644]
src/pxe.c/main.h [new file with mode: 0644]
src/pxe.c/printf.c [new file with mode: 0644]
src/pxe.c/pxe.c [new file with mode: 0644]
src/pxe.c/pxe.h [new file with mode: 0644]
src/registry.c [new file with mode: 0644]

diff --git a/Makefile b/Makefile
new file mode 100644 (file)
index 0000000..de88e18
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,113 @@
+INCLUDES := $(shell echo | cpp -v 2>&1 | sed -n '/\#include "..." search starts here:/,/End of search list./p' | grep "^ " | sed "s/^ \(.*\)$$/-I\1\/ddk/" | tr "\n" " " | sed "s/ $$//" | sed ":start;s/\/[^\/]*\/\.\.\//\//;t start")\r
+\r
+# Next line is duplicated in config.bat, edit both when adding files.\r
+c := driver.c registry.c bus.c disk.c aoe.c protocol.c debug.c\r
+h := driver.h aoe.h protocol.h mount.h portable.h\r
+\r
+# This is also duplicated in config.bat.\r
+# The c style aoe.0 is not yet stable enough to use.\r
+PXESTYLE := asm\r
+#PXESTYLE := c\r
+\r
+all: bin/aoe.0 bin/loader32.exe bin/aoe32.sys bin/aoe.exe bin/aoe.inf bin/txtsetup.oem\r
+\r
+clean:\r
+       @rm -rf src/obj src/pxe.asm/obj src/pxe.c/obj bin\r
+\r
+dist:\r
+       @sh -c "unset \`set | cut -f 1 -d \"=\" | egrep -v \"PATH|COMSPEC\"\` 2> /dev/null ; cmd /c makedist.bat"\r
+\r
+free: bin/aoe.inf bin/txtsetup.oem $(addprefix src/,$c $h) Makefile\r
+       @sh -c "unset \`set | cut -f 1 -d \"=\" | egrep -v \"PATH|COMSPEC\"\` 2> /dev/null ; cmd /c makefree.bat"\r
+       @touch -r Makefile $(wildcard bin/*.sys)\r
+       \r
+checked: bin/aoe.inf bin/txtsetup.oem $(addprefix src/,$c $h) Makefile\r
+       @sh -c "unset \`set | cut -f 1 -d \"=\" | egrep -v \"PATH|COMSPEC\"\` 2> /dev/null ; cmd /c makechecked.bat"\r
+       @touch -r Makefile $(wildcard bin/*.sys)\r
+\r
+bin/aoe.0: src/pxe.$(PXESTYLE)/aoe.0 Makefile\r
+       @mkdir -p bin\r
+       cp src/pxe.$(PXESTYLE)/aoe.0 bin\r
+\r
+src/pxe.$(PXESTYLE)/aoe.0: $(wildcard src/pxe.$(PXESTYLE)/*.c) $(wildcard src/pxe.$(PXESTYLE)/*.h) $(wildcard src/pxe.$(PXESTYLE)/*.S) src/pxe.$(PXESTYLE)/aoe.ld src/pxe.$(PXESTYLE)/Makefile Makefile\r
+       rm -rf src/pxe.$(PXESTYLE)/aoe.0\r
+       make -C src/pxe.$(PXESTYLE)\r
+\r
+bin/aoe.inf bin/txtsetup.oem: makeinf.bat Makefile\r
+       @sh -c "unset \`set | cut -f 1 -d \"=\" | egrep -v \"PATH|COMSPEC\"\` 2> /dev/null ; cmd /c makeinf.bat ; exit 0" >/dev/null 2>&1\r
+       touch bin/aoe.inf\r
+       touch bin/txtsetup.oem\r
+\r
+src/obj/loader32.o: src/loader.c src/portable.h Makefile\r
+       @mkdir -p src/obj\r
+       @rm -rf src/obj/loader32.o bin/loader32.exe bin/loader64.exe\r
+       gcc $(INCLUDES) -c -Wall src/loader.c -o src/obj/loader32.o\r
+\r
+bin/loader32.exe: src/obj/loader32.o Makefile\r
+       @mkdir -p bin\r
+       @rm -rf bin/loader32.exe bin/loader64.exe\r
+       gcc $(INCLUDES) -Wall src/obj/loader32.o -o bin/loader32.exe -lsetupapi\r
+       strip bin/loader32.exe\r
+\r
+src/obj/mount.o: src/mount.c src/portable.h src/mount.h Makefile\r
+       @mkdir -p src/obj\r
+       @rm -rf src/obj/mount.o bin/aoe.exe\r
+       gcc -Wall -c src/mount.c -o src/obj/mount.o\r
+\r
+bin/aoe.exe: src/obj/mount.o Makefile\r
+       @mkdir -p bin\r
+       @rm -rf bin/aoe.exe\r
+       gcc -Wall src/obj/mount.o -o bin/aoe.exe\r
+       strip bin/aoe.exe\r
+\r
+src/obj/driver.o: src/driver.c src/portable.h src/driver.h Makefile\r
+       @mkdir -p src/obj\r
+       @rm -rf src/obj/driver.o src/obj/aoe.tmp src/obj/aoe.exp bin/aoe32.sys bin/aoe64.sys bin/aoe32.pdb bin/aoe64.pdb bin/loader64.exe\r
+       gcc $(INCLUDES) -c -Wall src/driver.c -o src/obj/driver.o\r
+\r
+src/obj/registry.o: src/registry.c src/portable.h Makefile\r
+       @mkdir -p src/obj\r
+       @rm -rf src/obj/registry.o src/obj/aoe.tmp src/obj/aoe.exp bin/aoe32.sys bin/aoe64.sys bin/aoe32.pdb bin/aoe64.pdb bin/loader64.exe\r
+       gcc $(INCLUDES) -c -Wall src/registry.c -o src/obj/registry.o\r
+\r
+src/obj/bus.o: src/bus.c src/portable.h src/driver.h src/aoe.h src/mount.h Makefile\r
+       @mkdir -p src/obj\r
+       @rm -rf src/obj/bus.o src/obj/aoe.tmp src/obj/aoe.exp bin/aoe32.sys bin/aoe64.sys bin/aoe32.pdb bin/aoe64.pdb bin/loader64.exe\r
+       gcc $(INCLUDES) -c -Wall src/bus.c -o src/obj/bus.o\r
+\r
+src/obj/disk.o: src/disk.c src/portable.h src/driver.h src/aoe.h Makefile\r
+       @mkdir -p src/obj\r
+       @rm -rf src/obj/disk.o src/obj/aoe.tmp src/obj/aoe.exp bin/aoe32.sys bin/aoe64.sys bin/aoe32.pdb bin/aoe64.pdb bin/loader64.exe\r
+       gcc $(INCLUDES) -c -Wall src/disk.c -o src/obj/disk.o\r
+\r
+src/obj/aoe.o: src/aoe.c src/portable.h src/driver.h src/aoe.h src/protocol.h Makefile\r
+       @mkdir -p src/obj\r
+       @rm -rf src/obj/aoe.o src/obj/aoe.tmp src/obj/aoe.exp bin/aoe32.sys bin/aoe64.sys bin/aoe32.pdb bin/aoe64.pdb bin/loader64.exe\r
+       gcc $(INCLUDES) -c -Wall src/aoe.c -o src/obj/aoe.o\r
+\r
+src/obj/protocol.o: src/protocol.c src/portable.h src/driver.h src/aoe.h src/protocol.h Makefile\r
+       @mkdir -p src/obj\r
+       @rm -rf src/obj/protocol.o src/obj/aoe.tmp src/obj/aoe.exp bin/aoe32.sys bin/aoe64.sys bin/aoe32.pdb bin/aoe64.pdb bin/loader64.exe\r
+       gcc $(INCLUDES) -c -Wall src/protocol.c -o src/obj/protocol.o\r
+\r
+src/obj/debug.o: src/debug.c src/portable.h src/driver.h src/mount.h Makefile\r
+       @mkdir -p src/obj\r
+       @rm -rf src/obj/debug.o src/obj/aoe.tmp src/obj/aoe.exp bin/aoe32.sys bin/aoe64.sys bin/aoe32.pdb bin/aoe64.pdb bin/loader64.exe\r
+       gcc $(INCLUDES) -c -Wall src/debug.c -o src/obj/debug.o\r
+\r
+src/obj/aoe.tmp: src/obj/driver.o src/obj/registry.o src/obj/bus.o src/obj/disk.o src/obj/aoe.o src/obj/protocol.o src/obj/debug.o Makefile\r
+       @mkdir -p src/obj\r
+       @rm -rf src/obj/aoe.tmp src/obj/aoe.exp bin/aoe32.sys bin/aoe64.sys bin/aoe32.pdb bin/aoe64.pdb bin/loader64.exe\r
+       @gcc -Wall src/obj/driver.o src/obj/registry.o src/obj/bus.o src/obj/disk.o src/obj/aoe.o src/obj/protocol.o src/obj/debug.o -Wl,--base-file,src/obj/aoe.tmp -Wl,--entry,_DriverEntry@8 -nostartfiles -nostdlib -lntoskrnl -lhal -lndis -o null\r
+       @rm -rf null.exe\r
+\r
+src/obj/aoe.exp: src/obj/aoe.tmp Makefile\r
+       @mkdir -p src/obj\r
+       @rm -rf src/obj/aoe.exp bin/aoe32.sys bin/aoe64.sys bin/aoe32.pdb bin/aoe64.pdb bin/loader64.exe\r
+       @dlltool --dllname aoe32.sys --base-file src/obj/aoe.tmp --output-exp src/obj/aoe.exp\r
+\r
+bin/aoe32.sys: src/obj/driver.o src/obj/registry.o src/obj/bus.o src/obj/disk.o src/obj/aoe.o src/obj/protocol.o src/obj/debug.o src/obj/aoe.exp Makefile\r
+       @mkdir -p bin\r
+       @rm -rf bin/aoe32.sys bin/aoe64.sys bin/aoe32.pdb bin/aoe64.pdb bin/loader64.exe\r
+       @gcc -Wall src/obj/driver.o src/obj/registry.o src/obj/bus.o src/obj/disk.o src/obj/aoe.o src/obj/protocol.o src/obj/debug.o -Wl,--subsystem,native -Wl,--entry,_DriverEntry@8 -Wl,src/obj/aoe.exp -mdll -nostartfiles -nostdlib -lntoskrnl -lhal -lndis -o bin/aoe32.sys\r
+#      strip bin/aoe32.sys\r
diff --git a/changelog.txt b/changelog.txt
new file mode 100644 (file)
index 0000000..265fc8e
--- /dev/null
@@ -0,0 +1,13 @@
+0.97g:\r
+- added changelog.txt\r
+- fixed resend scheduler\r
+- some Makefile fixes\r
+- fixed some spelling in readme.txt\r
+- some changes to mount to not wait for a key after mount and unmount\r
+\r
+0.97f:\r
+- Initial public release\r
+- revamped Makefile and added bat files to make compiling user-friendly\r
+- Implemented new scheduler\r
+- Implemented multiple disk unmount support (still buggy!)\r
+- added alpha c version of aoe.0 (still disabled in favor of the asm version)\r
diff --git a/config.bat b/config.bat
new file mode 100644 (file)
index 0000000..3f0ffe2
--- /dev/null
@@ -0,0 +1,6 @@
+rem This is the root directory of the ddk.\r
+set ddkdir=d:\winddk\r
+\r
+rem Next two lines are duplicated in Makefile, edit both when adding files or changing pxe style.\r
+set c=driver.c registry.c bus.c disk.c aoe.c protocol.c debug.c\r
+set pxestyle=asm\r
diff --git a/gpl.txt b/gpl.txt
new file mode 100644 (file)
index 0000000..94a9ed0
--- /dev/null
+++ b/gpl.txt
@@ -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/makechecked.bat b/makechecked.bat
new file mode 100644 (file)
index 0000000..278f83a
--- /dev/null
@@ -0,0 +1,5 @@
+@echo off\r
+mkdir bin 2>nul\r
+cmd /c makeutils\r
+cmd /c makedriver c 32\r
+cmd /c makedriver c 64\r
diff --git a/makedist.bat b/makedist.bat
new file mode 100644 (file)
index 0000000..79798e4
--- /dev/null
@@ -0,0 +1,16 @@
+@echo off\r
+call config.bat\r
+rd /s /q bin 2>nul\r
+rd /s /q src\obj 2>nul\r
+rd /s /q src\pxe.asm\obj 2>nul\r
+rd /s /q src\pxe.c\obj 2>nul\r
+mkdir bin 2>nul\r
+cmd /c makeutils\r
+cmd /c makeinf\r
+cmd /c makedriver f 32\r
+cmd /c makedriver f 64\r
+del bin\loader32.exe\r
+del bin\loader64.exe\r
+del bin\aoe32.pdb\r
+del bin\aoe64.pdb\r
+copy src\pxe.%pxestyle%\aoe.0 bin\r
diff --git a/makedriver.bat b/makedriver.bat
new file mode 100644 (file)
index 0000000..2acdf6a
--- /dev/null
@@ -0,0 +1,83 @@
+@echo off\r
+if "%1" == "" goto help\r
+if "%2" == "" goto help\r
+if "%1" == "/?" goto help\r
+\r
+if "%1" == "f" goto next_1\r
+if "%1" == "c" goto next_1\r
+if "%1" == "32" goto next_2\r
+if "%1" == "64" goto next_2\r
+goto help\r
+\r
+:next_1\r
+if "%1" == "f" set arg1=fre\r
+if "%1" == "c" set arg1=chk\r
+if "%1" == "f" set obj=fre\r
+if "%1" == "c" set obj=chk\r
+if "%2" == "32" goto next_1_ok\r
+if "%2" == "64" goto next_1_ok\r
+goto help\r
+\r
+:next_1_ok\r
+if "%2" == "32" set arg2=w2k\r
+if "%2" == "64" set arg2=wnet amd64\r
+if "%2" == "32" set arch=i386\r
+if "%2" == "64" set arch=amd64\r
+if "%2" == "32" set name=aoe32\r
+if "%2" == "64" set name=aoe64\r
+if "%2" == "32" set obj=%obj%_w2k_x86\r
+if "%2" == "64" set obj=%obj%_wnet_amd64\r
+goto run\r
+\r
+:next_2\r
+if "%1" == "32" set arg2=w2k\r
+if "%1" == "64" set arg2=wnet amd64\r
+if "%1" == "32" set arch=i386\r
+if "%1" == "64" set arch=amd64\r
+if "%1" == "32" set name=aoe32\r
+if "%1" == "64" set name=aoe64\r
+if "%1" == "32" set obj=w2k_x86\r
+if "%1" == "64" set obj=wnet_amd64\r
+if "%2" == "f" goto next_2_ok\r
+if "%2" == "c" goto next_2_ok\r
+goto help\r
+\r
+:next_2_ok\r
+if "%2" == "f" set arg1=fre\r
+if "%2" == "c" set arg1=chk\r
+if "%2" == "f" set obj=fre_%obj%\r
+if "%2" == "c" set obj=chk_%obj%\r
+goto run\r
+\r
+:help\r
+echo.\r
+echo Usage: "makedriver [f|c] [32|64]"\r
+echo.\r
+goto end\r
+\r
+:run\r
+mkdir bin 2>nul\r
+call config.bat\r
+pushd .\r
+call %ddkdir%\bin\setenv.bat %ddkdir% %arg1% %arg2%\r
+popd\r
+\r
+cd src\r
+echo !INCLUDE $(NTMAKEENV)\makefile.def > makefile\r
+echo TARGETNAME=%name% > sources\r
+echo TARGETTYPE=DRIVER >> sources\r
+echo TARGETPATH=obj >> sources\r
+echo TARGETLIBS=$(DDK_LIB_PATH)\\ndis.lib >> sources\r
+echo SOURCES=%c% >> sources\r
+build\r
+copy obj%obj%\%arch%\%name%.sys ..\bin >nul\r
+copy obj%obj%\%arch%\%name%.pdb ..\bin >nul\r
+del makefile\r
+del sources\r
+del build%obj%.log\r
+del build%obj%.wrn 2>nul\r
+del build%obj%.err 2>nul\r
+rd /s /q obj%obj%\r
+cd ..\r
+\r
+:end\r
diff --git a/makefree.bat b/makefree.bat
new file mode 100644 (file)
index 0000000..1ea5034
--- /dev/null
@@ -0,0 +1,5 @@
+@echo off\r
+mkdir bin 2>nul\r
+cmd /c makeutils\r
+cmd /c makedriver f 32\r
+cmd /c makedriver f 64\r
diff --git a/makeinf.bat b/makeinf.bat
new file mode 100644 (file)
index 0000000..79db9f6
--- /dev/null
@@ -0,0 +1,85 @@
+@echo off\r
+mkdir bin 2>nul\r
+\r
+echo [Version] > bin/aoe.inf\r
+echo Signature="$Windows NT$" >> bin/aoe.inf\r
+echo Class=SCSIAdapter >> bin/aoe.inf\r
+echo ClassGUID={4D36E97B-E325-11CE-BFC1-08002BE10318} >> bin/aoe.inf\r
+echo Provider=AoE >> bin/aoe.inf\r
+echo CatalogFile=aoe.cat >> bin/aoe.inf\r
+echo DriverVer=01/01/2006,1.0 >> bin/aoe.inf\r
+echo. >> bin/aoe.inf\r
+echo [Manufacturer] >> bin/aoe.inf\r
+echo AoE=AoEDriver,,NTamd64 >> bin/aoe.inf\r
+echo.  >> bin/aoe.inf\r
+echo [AoEDriver] >> bin/aoe.inf\r
+echo "AoE Driver"=AoE,AoE >> bin/aoe.inf\r
+echo. >> bin/aoe.inf\r
+echo [AoEDriver.NTamd64] >> bin/aoe.inf\r
+echo "AoE Driver"=AoE.NTamd64,AoE >> bin/aoe.inf\r
+echo. >> bin/aoe.inf\r
+echo [SourceDisksNames] >> bin/aoe.inf\r
+echo 0="Install Disk" >> bin/aoe.inf\r
+echo. >> bin/aoe.inf\r
+echo [SourceDisksFiles] >> bin/aoe.inf\r
+echo aoe.exe=0 >> bin/aoe.inf\r
+echo aoe32.sys=0 >> bin/aoe.inf\r
+echo aoe64.sys=0 >> bin/aoe.inf\r
+echo. >> bin/aoe.inf\r
+echo [DestinationDirs] >> bin/aoe.inf\r
+echo Files.Driver=12 >> bin/aoe.inf\r
+echo Files.Driver.NTamd64=12 >> bin/aoe.inf\r
+echo Files.Tools=11 >> bin/aoe.inf\r
+echo. >> bin/aoe.inf\r
+echo [Files.Driver] >> bin/aoe.inf\r
+echo aoe32.sys >> bin/aoe.inf\r
+echo. >> bin/aoe.inf\r
+echo [Files.Driver.NTamd64] >> bin/aoe.inf\r
+echo aoe64.sys >> bin/aoe.inf\r
+echo. >> bin/aoe.inf\r
+echo [Files.Tools] >> bin/aoe.inf\r
+echo aoe.exe >> bin/aoe.inf\r
+echo. >> bin/aoe.inf\r
+echo [AoE] >> bin/aoe.inf\r
+echo CopyFiles=Files.Driver,Files.Tools >> bin/aoe.inf\r
+#echo DelReg=DelReg >> bin/aoe.inf\r
+echo. >> bin/aoe.inf\r
+echo [AoE.NTamd64] >> bin/aoe.inf\r
+echo CopyFiles=Files.Driver.NTamd64,Files.Tools >> bin/aoe.inf\r
+#echo DelReg=DelReg >> bin/aoe.inf\r
+echo. >> bin/aoe.inf\r
+echo [AoE.Services] >> bin/aoe.inf\r
+echo AddService=AoE,0x00000002,Service >> bin/aoe.inf\r
+echo. >> bin/aoe.inf\r
+echo [AoE.NTamd64.Services] >> bin/aoe.inf\r
+echo AddService=AoE,0x00000002,Service.NTamd64 >> bin/aoe.inf\r
+echo. >> bin/aoe.inf\r
+echo [Service] >> bin/aoe.inf\r
+echo ServiceType=0x00000001 >> bin/aoe.inf\r
+echo StartType=0x00000000 >> bin/aoe.inf\r
+echo ErrorControl=0x00000001 >> bin/aoe.inf\r
+echo ServiceBinary=%%12%%\aoe32.sys >> bin/aoe.inf\r
+#echo LoadOrderGroup=NDIS >> bin/aoe.inf\r
+echo. >> bin/aoe.inf\r
+echo [Service.NTamd64] >> bin/aoe.inf\r
+echo ServiceType=0x00000001 >> bin/aoe.inf\r
+echo StartType=0x00000000 >> bin/aoe.inf\r
+echo ErrorControl=0x00000001 >> bin/aoe.inf\r
+echo ServiceBinary=%%12%%\aoe64.sys >> bin/aoe.inf\r
+#echo LoadOrderGroup=NDIS >> bin/aoe.inf\r
+#echo. >> bin/aoe.inf\r
+#echo [DelReg] >> bin/aoe.inf\r
+#echo HKLM,SYSTEM\CurrentControlSet\Services\atapi,Group >> bin/aoe.inf\r
+\r
+echo [Disks] > bin/txtsetup.oem\r
+echo disk = "AOE DISK",\aoe.inf,\ >> bin/txtsetup.oem\r
+echo. >> bin/txtsetup.oem\r
+echo [Defaults] >> bin/txtsetup.oem\r
+echo scsi = AOE >> bin/txtsetup.oem\r
+echo. >> bin/txtsetup.oem\r
+echo [scsi] >> bin/txtsetup.oem\r
+echo AOE = "AoE Driver" >> bin/txtsetup.oem\r
+echo. >> bin/txtsetup.oem\r
+echo [Files.scsi.AOE] >> bin/txtsetup.oem\r
+echo driver = disk,aoe32.sys,AoE >> bin/txtsetup.oem\r
+echo inf = disk,aoe.inf >> bin/txtsetup.oem\r
diff --git a/makeutils.bat b/makeutils.bat
new file mode 100644 (file)
index 0000000..3e6f0a3
--- /dev/null
@@ -0,0 +1,17 @@
+@echo off\r
+mkdir bin 2>nul\r
+call config.bat\r
+cd src\r
+pushd .\r
+call %ddkdir%\bin\setenv.bat %ddkdir% w2k\r
+popd\r
+cl /I%CRT_INC_PATH% /DWIN32_LEAN_AND_MEAN mount.c /Fe..\bin\aoe.exe /link /LIBPATH:%DDK_LIB_DEST%\i386 /LIBPATH:%Lib%\crt\i386 bufferoverflowU.lib\r
+del mount.obj\r
+cl /I%CRT_INC_PATH% /DWIN32_LEAN_AND_MEAN loader.c /Fe..\bin\loader32.exe /link /LIBPATH:%DDK_LIB_DEST%\i386 /LIBPATH:%Lib%\crt\i386 setupapi.lib bufferoverflowU.lib\r
+del loader.obj\r
+pushd .\r
+call %ddkdir%\bin\setenv.bat %ddkdir% wnet amd64\r
+popd\r
+cl /I%CRT_INC_PATH% /DWIN32_LEAN_AND_MEAN loader.c /Fe..\bin\loader64.exe /link /LIBPATH:%DDK_LIB_DEST%\%_BUILDARCH% /LIBPATH:%Lib%\crt\%_BUILDARCH% setupapi.lib bufferoverflowU.lib\r
+del loader.obj\r
+cd ..\r
diff --git a/readme.txt b/readme.txt
new file mode 100644 (file)
index 0000000..608478e
--- /dev/null
@@ -0,0 +1,130 @@
+WinAoE (http://winaoe.org/)\r
+\r
+Diskless AoE Driver for:\r
+ Windows 2000\r
+ Windows XP\r
+ Windows XP 64bit\r
+ Windows 2003\r
+ Windows 2003 64bit\r
+ Windows 2003R2 *\r
+ Windows 2003R2 64bit *\r
+ Windows Vista\r
+ Windows Vista 64bit *\r
+*) Not yet fully tested, should work, but need more confirmation.\r
+\r
+\r
+This driver and code is free software, released under the GPL v3. See gpl.txt and http://www.gnu.org/ for more information.\r
+This readme.txt is slightly outdated, still need to update it with all new options added after 0.95.\r
+In general, the installing information still is the same though.\r
+\r
+\r
+This driver will take diskless net booting and general AoE access to the windows world.\r
+To use this driver you must either image a working installation with the driver installed or use a real hard disk with an installation with the driver installed.\r
+Using the driver in Windows Setup mode is not yet supported (this might change in the future using RIS).\r
+\r
+\r
+Installing AoE:\r
+For normal AoE disk mounting, you can simply install the AoE driver through "add new hardware -> choose -> SCSI" and use the aoe utility to scan and mount available blades.\r
+Run aoe from a command window to see the options.\r
+\r
+\r
+Installing Diskless AoE:\r
+\r
+Server side setup:\r
+To make it all work, you need Etherboot capable NICs, either getting Etherboot over PXE or from another media as a floppy.\r
+We'll take the pure PXE road here, to use another media, you can ignore some setup steps here.\r
+The example here uses an Intel pro 1000 card, change to reflect your own settings where needed.\r
+Also, the example here is mainly based on a Slackware Linux server, but it should be very similar for other distributions.\r
+For windows servers, scroll down.\r
+\r
+1. make a tftpboot directory in /, add the aoe.0 file to it and enable the tftp daemon\r
+\r
+  mkdir /tftpboot\r
+  cp /path/to/aoe.0 /tftpboot\r
+  add the line "tftp dgram udp wait root /usr/sbin/in.tftpd in.tftpd -s /tftpboot -r blksize" to /etc/inetd.conf\r
+  /etc/rc.d/rc.inetd restart\r
+\r
+2.a make  an Etherboot zpxe image for your NIC on http://rom-o-matic.net/\r
+   .. or ..\r
+2.b download and unpack the Etherboot source package, compile the correct zpxe driver for your NIC and add the file to tftpboot\r
+\r
+  wget http://heanet.dl.sourceforge.net/sourceforge/etherboot/etherboot-5.4.2.tar.bz2\r
+  tar xfj etherboot-5.4.2.tar.bz2\r
+  cd etherboot-5.4.2\r
+  make bin/e1000.zpxe\r
+  cp bin/e1000.zpxe /tftpboot\r
+\r
+3. edit your dhcp configuration to look like this:\r
+\r
+    host Client {\r
+      hardware ethernet 00:01:02:03:04:05;                     # the mac address of your boot NIC\r
+      fixed-address 192.168.0.3;                               # your client's IP\r
+      if substring (option vendor-class-identifier, 0, 9) != "Etherboot" {\r
+        filename "/e1000.zpxe";                                        # the file made in step 2\r
+      } else {\r
+        filename "/aoe.0";                                     # aoe.0 file found in the archive\r
+      }\r
+      # next is root-path, this is dhcp option 17 (0x11) if you have to manually specify it.\r
+      option root-path "aoe:e0.0";                             # major and minor id of vblade\r
+    }\r
+\r
+4. restart dhcpd\r
+\r
+  killall -9 dhcpd\r
+  dhcpd\r
+\r
+\r
+This concludes the server side setup.\r
+The only thing needed besides this the target AoE device, for instance vblade or AoE hardware from http://www.coraid.com/\r
+Vblade is an Linux software version of the latter.\r
+\r
+\r
+Client setup:\r
+On an installed system, install the AoE driver through "add new hardware -> choose -> SCSI"\r
+After installing, go in regedit to HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\r
+There, search the key for the boot NIC (in the case of an Intel E1000 it would be E1000, the one in VMware is VMXNET) and change the "Start" key to 0 (boot).\r
+The AoE driver will automatically load itself before atapi.sys, but it will only boot from a netboot disk if started from the net through aoe.0.\r
+This means you can, for instance, install on a real hard disk, put the disk in a server or Coraid enclosure, netboot from it, and when you want to boot from it in a normal way (attached to the PC itself) you can put it back and let it boot as normal.\r
+\r
+\r
+Client imaging in vblade:\r
+The image to boot from can be any file or block device on the Linux server.\r
+The driver will take the heads/sectors/cylinders automatically from the partition table, so any real or fake disk image will do (if there is no partition table, it will default to 63 sectors/track, 255 heads).\r
+The easiest way to do get a workable block device is taking a hard disk of an installed system or a VMware full disk image, but also own made images, partitioned in Linux fdisk, will work.\r
+\r
+There are a few ways to make an image, with the easiest being just taking a live working hard disk and using that block device, or making an image (with dd) from a working disk to a file on the Linux server.\r
+Another handy way is to install on a small partition, dd the partition AND the 1st 63 sectors before that partition to a Linux block device (raid devices for instance), and lastly use the Linux ntfsresize util to expand it to the full device.\r
+This option lets you store a small (4GB) file as a fast way to reinstall, yet have a big raid disk to install to.\r
+\r
+\r
+Windows server:\r
+All above steps concerning dhcpd and tftp could also be run on a windows server without any problems, check your manual how.However, vblade of course does not run on windows, so you must use either Coraid's enclosures, or find a working AoE windows target.\r
+To counter these issues just use a proper server OS (Linux/BSD/other UNIX like systems).\r
+\r
+\r
+Compiling:\r
+To compile this you need either MSYS or the windows 2003 DDK, preferably both.\r
+Set the path to the DDK in config.bat and run the bat files makefree or makechecked to build everything but aoe.0.\r
+aoe.0 will not be deleted and is prebuild in the package, so you can get away with only using the DDK.\r
+To build aoe.0 you need MSYS or a Linux box (type make in the pxe.asm or pxe.c dir in Linux to compile it).\r
+MSYS can also build the driver itself, but only the 32bit version, and it will not generate windbg symbol files.\r
+Also, the MSYS generated driver has a higher chance of failing, due to compiler bugs.\r
+When compiling the driver with makefree/makechecked or in MSYS with make, a loader32/64.exe will also be build to quickly install the driver without going through the control panel.\r
+This is mostly useful in virtual environments (VMware) where the disk is non-persistent.\r
+With it you can simply reboot the virtual machine to restart anew, and start loader.32 to boot it (using dbgview http://technet.microsoft.com/en-us/sysinternals/bb896647.aspx to see debug output)\r
+\r
+Lastly, the txtsetup.oem file is not needed as of yet, it is part of the "to be" RIS function (if that will ever work)\r
+\r
+\r
+TODO's, Notes and known issues:\r
+0. Big TODO... fix this readme.txt (like adding compile information).\r
+1. you CAN NOT change the position of the NIC in the PCI slots! (you should however be able to change NICs around by adding a second NIC, booting over the first, setting the second to start at boot and then removing the first)\r
+2. There might be ways in the future to install directly to Coraid hardware/vblade using RIS, but options are limited and might not work.\r
+3. The driver will not work with the original drive attached. to fix this, either remove the "group" parameter in the service entry in the registry of the driver on which the disk is attached (for atapi this is done on installing the AoE driver, for SATA, SCSI and others, search the correct service), or zero out the MBR of the drive.\r
+4. adding new PCI cards might be slow (need confirmation on this).\r
+5. uninstall StarPorts AoE driver for now, they conflict. don't know why (StarPorts fault, that's the one to crash after we have loaded).\r
+6. qemu, virtualbox and in some cases real hardware fails with lots of PacketAllocation errors, unknown cause as of yet (happens in VMware on windows 2000 too).\r
+7. User friendliness is lacking\r
+8. Client trunking and Server trunking is not yet enabled.\r
+9. aoe.0 does not work with Vista yet, use gPXE's AoE support for now.\r
+10. unmounting when multiple disks are mounted may cause a BSOD. unmounting when only a single disk is mounted should be ok.\r
diff --git a/src/aoe.c b/src/aoe.c
new file mode 100644 (file)
index 0000000..f4205e6
--- /dev/null
+++ b/src/aoe.c
@@ -0,0 +1,720 @@
+/*\r
+  Copyright 2006-2008, V.\r
+  For contact information, see http://winaoe.org/\r
+\r
+  This file is part of WinAoE.\r
+\r
+  WinAoE is free software: you can redistribute it and/or modify\r
+  it under the terms of the GNU General Public License as published by\r
+  the Free Software Foundation, either version 3 of the License, or\r
+  (at your option) any later version.\r
+\r
+  WinAoE is distributed in the hope that it will be useful,\r
+  but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+  GNU General Public License for more details.\r
+\r
+  You should have received a copy of the GNU General Public License\r
+  along with WinAoE.  If not, see <http://www.gnu.org/licenses/>.\r
+*/\r
+\r
+#include "portable.h"\r
+#include <ntddk.h>\r
+#include "aoe.h"\r
+#include "driver.h"\r
+#include "protocol.h"\r
+\r
+NTSTATUS STDCALL ZwWaitForSingleObject(IN HANDLE Handle, IN BOOLEAN Alertable, IN PLARGE_INTEGER Timeout OPTIONAL);\r
+\r
+// from bus.c\r
+VOID STDCALL BusAddTarget(IN PUCHAR ClientMac, IN PUCHAR ServerMac, USHORT Major, UCHAR Minor, LONGLONG LBASize);\r
+VOID STDCALL BusCleanupTargetList();\r
+\r
+// in this file\r
+VOID STDCALL Thread(IN PVOID StartContext);\r
+\r
+#ifdef _MSC_VER\r
+#pragma pack(1)\r
+#endif\r
+typedef enum {RequestType, SearchDriveType} TAGTYPE, *PTAGTYPE;\r
+\r
+typedef struct _AOE {\r
+  UCHAR ReservedFlag:2;\r
+  UCHAR ErrorFlag:1;\r
+  UCHAR ResponseFlag:1;\r
+  UCHAR Ver:4;\r
+  UCHAR Error;\r
+  USHORT Major;\r
+  UCHAR Minor;\r
+  UCHAR Command;\r
+  UINT Tag;\r
+\r
+  UCHAR WriteAFlag:1;\r
+  UCHAR AsyncAFlag:1;\r
+  UCHAR Reserved1AFlag:2;\r
+  UCHAR DeviceHeadAFlag:1;\r
+  UCHAR Reserved2AFlag:1;\r
+  UCHAR ExtendedAFlag:1;\r
+  UCHAR Reserved3AFlag:1;\r
+  union {\r
+    UCHAR Err;\r
+    UCHAR Feature;\r
+  };\r
+  UCHAR Count;\r
+  union {\r
+    UCHAR Cmd;\r
+    UCHAR Status;\r
+  };\r
+\r
+  UCHAR Lba0;\r
+  UCHAR Lba1;\r
+  UCHAR Lba2;\r
+  UCHAR Lba3;\r
+  UCHAR Lba4;\r
+  UCHAR Lba5;\r
+  USHORT Reserved;\r
+\r
+  UCHAR Data[];\r
+} __attribute__((__packed__)) AOE, *PAOE;\r
+#ifdef _MSC_VER\r
+#pragma pack()\r
+#endif\r
+\r
+typedef struct _REQUEST {\r
+  REQUESTMODE Mode;\r
+  ULONG SectorCount;\r
+  PUCHAR Buffer;\r
+  PIRP Irp;\r
+  ULONG TagCount;\r
+  ULONG TotalTags;\r
+} REQUEST, *PREQUEST;\r
+\r
+typedef struct _TAG {\r
+  TAGTYPE Type;\r
+  PDEVICEEXTENSION DeviceExtension;\r
+  PREQUEST Request;\r
+  ULONG Id;\r
+  PAOE PacketData;\r
+  ULONG PacketSize;\r
+  LARGE_INTEGER FirstSendTime;\r
+  LARGE_INTEGER SendTime;\r
+  ULONG BufferOffset;\r
+  ULONG SectorCount;\r
+  struct _TAG *Next;\r
+  struct _TAG *Previous;\r
+} TAG, *PTAG;\r
+\r
+typedef struct _DISKSEARCH {\r
+  PDEVICEEXTENSION DeviceExtension;\r
+  PTAG Tag;\r
+  struct _DISKSEARCH *Next;\r
+} DISKSEARCH, *PDISKSEARCH;\r
+\r
+BOOLEAN Stop = FALSE;\r
+KSPIN_LOCK SpinLock;\r
+KEVENT ThreadSignalEvent;\r
+PTAG TagList = NULL;\r
+PTAG TagListLast = NULL;\r
+PTAG ProbeTag = NULL;\r
+PDISKSEARCH DiskSearchList = NULL;\r
+LONG OutstandingTags = 0;\r
+HANDLE ThreadHandle;\r
+\r
+NTSTATUS STDCALL AoEStart() {\r
+  NTSTATUS Status;\r
+  OBJECT_ATTRIBUTES ObjectAttributes;\r
+  PVOID ThreadObject;\r
+\r
+  DbgPrint("AoEStart\n");\r
+  if ((ProbeTag = (PTAG)ExAllocatePool(NonPagedPool, sizeof(TAG))) == NULL) {\r
+    DbgPrint("AddStart ExAllocatePool ProbeTag\n");\r
+    return STATUS_INSUFFICIENT_RESOURCES;\r
+  }\r
+  RtlZeroMemory(ProbeTag, sizeof(TAG));\r
+  ProbeTag->PacketSize = sizeof(AOE);\r
+  if ((ProbeTag->PacketData = (PAOE)ExAllocatePool(NonPagedPool, ProbeTag->PacketSize)) == NULL) {\r
+    DbgPrint("AddStart ExAllocatePool ProbeTag->PacketData\n");\r
+    ExFreePool(ProbeTag);\r
+  }\r
+  ProbeTag->SendTime.QuadPart = 0LL;\r
+  RtlZeroMemory(ProbeTag->PacketData, ProbeTag->PacketSize);\r
+  ProbeTag->PacketData->Ver = AOEPROTOCOLVER;\r
+  ProbeTag->PacketData->Major = htons((USHORT)-1);\r
+  ProbeTag->PacketData->Minor = (UCHAR)-1;\r
+  ProbeTag->PacketData->Cmd = 0xec;             // IDENTIFY DEVICE\r
+  ProbeTag->PacketData->Count = 1;\r
+\r
+  KeInitializeSpinLock(&SpinLock);\r
+  KeInitializeEvent(&ThreadSignalEvent, SynchronizationEvent, FALSE);\r
+\r
+  InitializeObjectAttributes(&ObjectAttributes, NULL, OBJ_KERNEL_HANDLE, NULL, NULL);\r
+  if (!NT_SUCCESS(Status = PsCreateSystemThread(&ThreadHandle, THREAD_ALL_ACCESS, &ObjectAttributes, NULL, NULL, Thread, NULL))) return Error("PsCreateSystemThread", Status);\r
+  if (!NT_SUCCESS(Status = ObReferenceObjectByHandle(ThreadHandle, THREAD_ALL_ACCESS, NULL, KernelMode, &ThreadObject, NULL))) {\r
+    ZwClose(ThreadHandle);\r
+    Error("ObReferenceObjectByHandle", Status);\r
+    Stop = TRUE;\r
+    KeSetEvent(&ThreadSignalEvent, 0, FALSE);\r
+  }\r
+  return Status;\r
+}\r
+\r
+VOID STDCALL AoEStop() {\r
+  NTSTATUS Status;\r
+  PDISKSEARCH DiskSearch, PreviousDiskSearch;\r
+  PTAG Tag;\r
+  KIRQL Irql;\r
+\r
+  DbgPrint("AoEStop\n");\r
+  if (!Stop) {\r
+    Stop = TRUE;\r
+    KeSetEvent(&ThreadSignalEvent, 0, FALSE);\r
+    if (!NT_SUCCESS(Status = ZwWaitForSingleObject(ThreadHandle, FALSE, NULL))) Error("AoEStop ZwWaitForSingleObject", Status);\r
+    ZwClose(ThreadHandle);\r
+  }\r
+\r
+  KeAcquireSpinLock(&SpinLock, &Irql);\r
+\r
+  DiskSearch = DiskSearchList;\r
+  while (DiskSearch != NULL) {\r
+    KeSetEvent(&DiskSearch->DeviceExtension->Disk.SearchEvent, 0, FALSE);\r
+    PreviousDiskSearch = DiskSearch;\r
+    DiskSearch = DiskSearch->Next;\r
+    ExFreePool(PreviousDiskSearch);\r
+  }\r
+\r
+  Tag = TagList;\r
+  while (Tag != NULL) {\r
+    if (Tag->Request != NULL && --Tag->Request->TagCount == 0) {\r
+      Tag->Request->Irp->IoStatus.Information = 0;\r
+      Tag->Request->Irp->IoStatus.Status = STATUS_CANCELLED;\r
+      IoCompleteRequest(Tag->Request->Irp, IO_NO_INCREMENT);\r
+      ExFreePool(Tag->Request);\r
+    }\r
+    if (Tag->Next == NULL) {\r
+      ExFreePool(Tag->PacketData);\r
+      ExFreePool(Tag);\r
+      Tag = NULL;\r
+    } else {\r
+      Tag = Tag->Next;\r
+      ExFreePool(Tag->Previous->PacketData);\r
+      ExFreePool(Tag->Previous);\r
+    }\r
+  }\r
+  TagList = NULL;\r
+  TagListLast = NULL;\r
+  ExFreePool(ProbeTag->PacketData);\r
+  ExFreePool(ProbeTag);\r
+\r
+  KeReleaseSpinLock(&SpinLock, Irql);\r
+}\r
+\r
+BOOLEAN STDCALL AoESearchDrive(IN PDEVICEEXTENSION DeviceExtension) {\r
+  PDISKSEARCH DiskSearch, DiskSearchWalker, PreviousDiskSearch;\r
+  LARGE_INTEGER Timeout, CurrentTime;\r
+  PTAG Tag, TagWalker;\r
+  KIRQL Irql, InnerIrql;\r
+  LARGE_INTEGER MaxSectorsPerPacketSendTime;\r
+  ULONG MTU;\r
+\r
+  if ((DiskSearch = (PDISKSEARCH)ExAllocatePool(NonPagedPool, sizeof(DISKSEARCH))) == NULL) {\r
+    DbgPrint("AoESearchBootDrive ExAllocatePool DiskSearch\n");\r
+    return FALSE;\r
+  }\r
+\r
+  DiskSearch->DeviceExtension = DeviceExtension;\r
+  DiskSearch->Next = NULL;\r
+  DeviceExtension->Disk.SearchState = SearchNIC;\r
+  KeResetEvent(&DeviceExtension->Disk.SearchEvent);\r
+\r
+  KeAcquireSpinLock(&SpinLock, &Irql);\r
+  if (DiskSearchList == NULL) {\r
+    DiskSearchList = DiskSearch;\r
+  } else {\r
+    DiskSearchWalker = DiskSearchList;\r
+    while (DiskSearchWalker->Next) DiskSearchWalker = DiskSearchWalker->Next;\r
+    DiskSearchWalker->Next = DiskSearch;\r
+  }\r
+  KeReleaseSpinLock(&SpinLock, Irql);\r
+\r
+  while (TRUE) {\r
+    Timeout.QuadPart = -500000LL;               // 500.000 * 100ns = 50.000.000 ns = 50ms\r
+    KeWaitForSingleObject(&DeviceExtension->Disk.SearchEvent, Executive, KernelMode, FALSE, &Timeout);\r
+    if (Stop) {\r
+      DbgPrint("AoESearchBootDrive cancled\n");\r
+      return FALSE;\r
+    }\r
+\r
+    KeAcquireSpinLock(&DeviceExtension->Disk.SpinLock, &Irql);\r
+    if (DeviceExtension->Disk.SearchState == SearchNIC) {\r
+      if (!ProtocolSearchNIC(DeviceExtension->Disk.ClientMac)) {\r
+        KeReleaseSpinLock(&DeviceExtension->Disk.SpinLock, Irql);\r
+        continue;\r
+      } else {\r
+        DeviceExtension->Disk.MTU = ProtocolGetMTU(DeviceExtension->Disk.ClientMac);\r
+        DeviceExtension->Disk.SearchState = GetSize;\r
+      }\r
+    }\r
+\r
+    if (DeviceExtension->Disk.SearchState == GettingSize) {\r
+      KeReleaseSpinLock(&DeviceExtension->Disk.SpinLock, Irql);\r
+      continue;\r
+    }\r
+    if (DeviceExtension->Disk.SearchState == GettingGeometry) {\r
+      KeReleaseSpinLock(&DeviceExtension->Disk.SpinLock, Irql);\r
+      continue;\r
+    }\r
+    if (DeviceExtension->Disk.SearchState == GettingMaxSectorsPerPacket) {\r
+      KeQuerySystemTime(&CurrentTime);\r
+      if (CurrentTime.QuadPart > MaxSectorsPerPacketSendTime.QuadPart + 2500000LL) {    // 2.500.000 * 100ns = 250.000.000 ns = 250ms\r
+        DbgPrint("No reply after 250ms for MaxSectorsPerPacket %d, giving up\n", DeviceExtension->Disk.MaxSectorsPerPacket);\r
+        DeviceExtension->Disk.MaxSectorsPerPacket--;\r
+        DeviceExtension->Disk.SearchState = Done;\r
+      } else {\r
+        KeReleaseSpinLock(&DeviceExtension->Disk.SpinLock, Irql);\r
+        continue;\r
+      }\r
+    }\r
+\r
+    if (DeviceExtension->Disk.SearchState == Done) {\r
+      KeAcquireSpinLock(&SpinLock, &InnerIrql);\r
+      TagWalker = TagList;\r
+      while (TagWalker != NULL && TagWalker != Tag) TagWalker = TagWalker->Next;\r
+      if (TagWalker != NULL) {\r
+        if (Tag->Previous == NULL) TagList = Tag->Next;\r
+        else Tag->Previous->Next = Tag->Next;\r
+        if (Tag->Next == NULL) TagListLast = Tag->Previous;\r
+        else Tag->Next->Previous = Tag->Previous;\r
+        OutstandingTags--;\r
+        if (OutstandingTags < 0) DbgPrint("!!OutstandingTags < 0 (AoESearchDrive)!!\n");\r
+        ExFreePool(Tag->PacketData);\r
+        ExFreePool(Tag);\r
+      }\r
+\r
+      if (DiskSearchList == NULL) {\r
+        DbgPrint("!!DiskSearchList == NULL!!\n");\r
+      } else {\r
+        DiskSearchWalker = DiskSearchList;\r
+        while (DiskSearchWalker && DiskSearchWalker->DeviceExtension != DeviceExtension) {\r
+          PreviousDiskSearch = DiskSearchWalker;\r
+          DiskSearchWalker = DiskSearchWalker->Next;\r
+        }\r
+        if (DiskSearchWalker) {\r
+          if (DiskSearchWalker == DiskSearchList) {\r
+            DiskSearchList = DiskSearchWalker->Next;\r
+          } else {\r
+            PreviousDiskSearch->Next = DiskSearchWalker->Next;\r
+          }\r
+          ExFreePool(DiskSearchWalker);\r
+        } else {\r
+          DbgPrint("!!Disk not found in DiskSearchList!!\n");\r
+        }\r
+      }\r
+\r
+      KeReleaseSpinLock(&SpinLock, InnerIrql);\r
+      KeReleaseSpinLock(&DeviceExtension->Disk.SpinLock, Irql);\r
+        DbgPrint("Disk size: %I64uM cylinders: %I64u heads: %u sectors: %u sectors per packet: %u\n",\r
+        DeviceExtension->Disk.LBADiskSize / 2048,\r
+        DeviceExtension->Disk.Cylinders,\r
+        DeviceExtension->Disk.Heads,\r
+        DeviceExtension->Disk.Sectors,\r
+        DeviceExtension->Disk.MaxSectorsPerPacket\r
+      );\r
+      return TRUE;\r
+    }\r
+\r
+    if ((Tag = (PTAG)ExAllocatePool(NonPagedPool, sizeof(TAG))) == NULL) {\r
+      DbgPrint("AoESearchBootDrive ExAllocatePool Tag\n");\r
+      KeReleaseSpinLock(&DeviceExtension->Disk.SpinLock, Irql);\r
+      continue;\r
+    }\r
+    RtlZeroMemory(Tag, sizeof(TAG));\r
+    Tag->Type = SearchDriveType;\r
+    Tag->DeviceExtension = DeviceExtension;\r
+    Tag->PacketSize = sizeof(AOE);\r
+    if ((Tag->PacketData = (PAOE)ExAllocatePool(NonPagedPool, Tag->PacketSize)) == NULL) {\r
+      DbgPrint("AoESearchBootDrive ExAllocatePool Tag->PacketData\n");\r
+      ExFreePool(Tag);\r
+      Tag = NULL;\r
+      KeReleaseSpinLock(&DeviceExtension->Disk.SpinLock, Irql);\r
+      continue;\r
+    }\r
+    RtlZeroMemory(Tag->PacketData, Tag->PacketSize);\r
+    Tag->PacketData->Ver = AOEPROTOCOLVER;\r
+    Tag->PacketData->Major = htons((USHORT)DeviceExtension->Disk.Major);\r
+    Tag->PacketData->Minor = (UCHAR)DeviceExtension->Disk.Minor;\r
+    Tag->PacketData->ExtendedAFlag = TRUE;\r
+\r
+    switch (DeviceExtension->Disk.SearchState) {\r
+      case GetSize:\r
+        Tag->PacketData->Cmd = 0xec;               // IDENTIFY DEVICE\r
+        Tag->PacketData->Count = 1;\r
+        DeviceExtension->Disk.SearchState = GettingSize;\r
+        break;\r
+      case GetGeometry:\r
+        Tag->PacketData->Cmd = 0x24;               // READ SECTOR\r
+        Tag->PacketData->Count = 1;\r
+        DeviceExtension->Disk.SearchState = GettingGeometry;\r
+        break;\r
+      case GetMaxSectorsPerPacket:\r
+        Tag->PacketData->Cmd = 0x24;               // READ SECTOR\r
+        Tag->PacketData->Count = (UCHAR)(++DeviceExtension->Disk.MaxSectorsPerPacket);\r
+        KeQuerySystemTime(&MaxSectorsPerPacketSendTime);\r
+        DeviceExtension->Disk.SearchState = GettingMaxSectorsPerPacket;\r
+        DeviceExtension->Disk.Timeout = 200000;\r
+        break;\r
+      default:\r
+        DbgPrint("AoESearchBootDrive Undefined SearchState!\n");\r
+        ExFreePool(Tag->PacketData);\r
+        ExFreePool(Tag);\r
+        KeReleaseSpinLock(&DeviceExtension->Disk.SpinLock, Irql);\r
+        continue;\r
+        break;\r
+    }\r
+\r
+    Tag->Next = NULL;\r
+    KeAcquireSpinLock(&SpinLock, &InnerIrql);\r
+    if (TagList == NULL) {\r
+      TagList = Tag;\r
+      Tag->Previous = NULL;\r
+    } else {\r
+      TagListLast->Next = Tag;\r
+      Tag->Previous = TagListLast;\r
+    }\r
+    TagListLast = Tag;\r
+    KeReleaseSpinLock(&SpinLock, InnerIrql);\r
+    KeReleaseSpinLock(&DeviceExtension->Disk.SpinLock, Irql);\r
+  }\r
+}\r
+\r
+NTSTATUS STDCALL AoERequest(IN PDEVICEEXTENSION DeviceExtension, IN REQUESTMODE Mode, IN LONGLONG StartSector, IN ULONG SectorCount, IN PUCHAR Buffer, IN PIRP Irp) {\r
+  PREQUEST Request;\r
+  PTAG Tag, NewTagList = NULL, PreviousTag = NULL;\r
+  KIRQL Irql;\r
+  ULONG i;\r
+\r
+  if (Stop) {\r
+    Irp->IoStatus.Information = 0;\r
+    Irp->IoStatus.Status = STATUS_CANCELLED;\r
+    IoCompleteRequest(Irp, IO_NO_INCREMENT);\r
+    return STATUS_CANCELLED;\r
+  }\r
+\r
+  if (SectorCount < 1) {\r
+    DbgPrint("AoERequest SectorCount < 1!!\n");\r
+    Irp->IoStatus.Information = 0;\r
+    Irp->IoStatus.Status = STATUS_CANCELLED;\r
+    IoCompleteRequest(Irp, IO_NO_INCREMENT);\r
+    return STATUS_CANCELLED;\r
+  }\r
+\r
+  if ((Request = (PREQUEST)ExAllocatePool(NonPagedPool, sizeof(REQUEST))) == NULL) {\r
+    DbgPrint("AoERequest ExAllocatePool Request\n");\r
+    Irp->IoStatus.Information = 0;\r
+    Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;\r
+    IoCompleteRequest(Irp, IO_NO_INCREMENT);\r
+    return STATUS_INSUFFICIENT_RESOURCES;\r
+  }\r
+  RtlZeroMemory(Request, sizeof(REQUEST));\r
+  Request->Mode = Mode;\r
+  Request->SectorCount = SectorCount;\r
+  Request->Buffer = Buffer;\r
+  Request->Irp = Irp;\r
+  Request->TagCount = 0;\r
+\r
+  for (i = 0; i < SectorCount; i += DeviceExtension->Disk.MaxSectorsPerPacket) {\r
+    if ((Tag = (PTAG)ExAllocatePool(NonPagedPool, sizeof(TAG))) == NULL) {\r
+      DbgPrint("AoERequest ExAllocatePool Tag\n");\r
+      Tag = NewTagList;\r
+      while (Tag != NULL) {\r
+        PreviousTag = Tag;\r
+        Tag = Tag->Next;\r
+        ExFreePool(PreviousTag->PacketData);\r
+        ExFreePool(PreviousTag);\r
+      }\r
+      ExFreePool(Request);\r
+      Irp->IoStatus.Information = 0;\r
+      Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;\r
+      IoCompleteRequest(Irp, IO_NO_INCREMENT);\r
+      return STATUS_INSUFFICIENT_RESOURCES;\r
+    }\r
+    RtlZeroMemory(Tag, sizeof(TAG));\r
+    Tag->Type = RequestType;\r
+    Tag->Request = Request;\r
+    Tag->DeviceExtension = DeviceExtension;\r
+    Request->TagCount++;\r
+    Tag->Id = 0;\r
+    Tag->BufferOffset = i * SECTORSIZE;\r
+    Tag->SectorCount = ((SectorCount - i) < DeviceExtension->Disk.MaxSectorsPerPacket?SectorCount - i:DeviceExtension->Disk.MaxSectorsPerPacket);\r
+    Tag->PacketSize = sizeof(AOE);\r
+    if (Mode == Write) Tag->PacketSize += Tag->SectorCount * SECTORSIZE;\r
+    if ((Tag->PacketData = (PAOE)ExAllocatePool(NonPagedPool, Tag->PacketSize)) == NULL) {\r
+      DbgPrint("AoERequest ExAllocatePool Tag->PacketData\n");\r
+      ExFreePool(Tag);\r
+      Tag = NewTagList;\r
+      while (Tag != NULL) {\r
+        PreviousTag = Tag;\r
+        Tag = Tag->Next;\r
+        ExFreePool(PreviousTag->PacketData);\r
+        ExFreePool(PreviousTag);\r
+      }\r
+      ExFreePool(Request);\r
+      Irp->IoStatus.Information = 0;\r
+      Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;\r
+      IoCompleteRequest(Irp, IO_NO_INCREMENT);\r
+      return STATUS_INSUFFICIENT_RESOURCES;\r
+    }\r
+    RtlZeroMemory(Tag->PacketData, Tag->PacketSize);\r
+    Tag->PacketData->Ver = AOEPROTOCOLVER;\r
+    Tag->PacketData->Major = htons((USHORT)DeviceExtension->Disk.Major);\r
+    Tag->PacketData->Minor = (UCHAR)DeviceExtension->Disk.Minor;\r
+    Tag->PacketData->Tag = 0;\r
+    Tag->PacketData->Command = 0;\r
+    Tag->PacketData->ExtendedAFlag = TRUE;\r
+    if (Mode == Read) {\r
+      Tag->PacketData->Cmd = 0x24;                 // READ SECTOR\r
+    } else {\r
+      Tag->PacketData->Cmd = 0x34;                 // WRITE SECTOR\r
+      Tag->PacketData->WriteAFlag = 1;\r
+    }\r
+    Tag->PacketData->Count = (UCHAR)Tag->SectorCount;\r
+    Tag->PacketData->Lba0 = (UCHAR)(((StartSector + i) >> 0) & 255);\r
+    Tag->PacketData->Lba1 = (UCHAR)(((StartSector + i) >> 8) & 255);\r
+    Tag->PacketData->Lba2 = (UCHAR)(((StartSector + i) >> 16) & 255);\r
+    Tag->PacketData->Lba3 = (UCHAR)(((StartSector + i) >> 24) & 255);\r
+    Tag->PacketData->Lba4 = (UCHAR)(((StartSector + i) >> 32) & 255);\r
+    Tag->PacketData->Lba5 = (UCHAR)(((StartSector + i) >> 40) & 255);\r
+\r
+    if (Mode == Write) RtlCopyMemory(Tag->PacketData->Data, &Buffer[Tag->BufferOffset], Tag->SectorCount * SECTORSIZE);\r
+    Tag->Previous = PreviousTag;\r
+    Tag->Next = NULL;\r
+    if (NewTagList == NULL) {\r
+      NewTagList = Tag;\r
+    } else {\r
+      PreviousTag->Next = Tag;\r
+    }\r
+    PreviousTag = Tag;\r
+  }\r
+  Request->TotalTags = Request->TagCount;\r
+\r
+  KeAcquireSpinLock(&SpinLock, &Irql);\r
+  if (TagListLast == NULL) {\r
+    TagList = NewTagList;\r
+  } else {\r
+    TagListLast->Next = NewTagList;\r
+    NewTagList->Previous = TagListLast;\r
+  }\r
+  TagListLast = Tag;\r
+\r
+  Irp->IoStatus.Information = 0;\r
+  Irp->IoStatus.Status = STATUS_PENDING;\r
+  IoMarkIrpPending(Irp);\r
+\r
+  KeReleaseSpinLock(&SpinLock, Irql);\r
+  KeSetEvent(&ThreadSignalEvent, 0, FALSE);\r
+  return STATUS_PENDING;\r
+}\r
+\r
+NTSTATUS STDCALL AoEReply(IN PUCHAR SourceMac, IN PUCHAR DestinationMac, IN PUCHAR Data, IN UINT DataSize) {\r
+  PAOE Reply = (PAOE)Data;\r
+  LONGLONG LBASize;\r
+  PTAG Tag;\r
+  KIRQL Irql;\r
+  BOOLEAN Found = FALSE;\r
+  LARGE_INTEGER CurrentTime;\r
+\r
+  if (!Reply->ResponseFlag) return STATUS_SUCCESS;\r
+\r
+  if (ProbeTag->Id == Reply->Tag) {\r
+    RtlCopyMemory(&LBASize, &Reply->Data[200], sizeof(LONGLONG));\r
+    BusAddTarget(DestinationMac, SourceMac, ntohs(Reply->Major), Reply->Minor, LBASize);\r
+    return STATUS_SUCCESS;\r
+  }\r
+\r
+  KeAcquireSpinLock(&SpinLock, &Irql);\r
+  if (TagList == NULL) {\r
+    KeReleaseSpinLock(&SpinLock, Irql);\r
+    return STATUS_SUCCESS;\r
+  }\r
+  Tag = TagList;\r
+  while (Tag != NULL) {\r
+    if ((Tag->Id == Reply->Tag) && (Tag->PacketData->Major == Reply->Major) && (Tag->PacketData->Minor == Reply->Minor)) {\r
+      Found = TRUE;\r
+      break;\r
+    }\r
+    Tag = Tag->Next;\r
+  }\r
+  if (!Found) {\r
+    KeReleaseSpinLock(&SpinLock, Irql);\r
+    return STATUS_SUCCESS;\r
+  } else {\r
+    if (Tag->Previous == NULL) TagList = Tag->Next;\r
+    else Tag->Previous->Next = Tag->Next;\r
+    if (Tag->Next == NULL) TagListLast = Tag->Previous;\r
+    else Tag->Next->Previous = Tag->Previous;\r
+    OutstandingTags--;\r
+    if (OutstandingTags < 0) DbgPrint("!!OutstandingTags < 0 (AoEReply)!!\n");\r
+    KeSetEvent(&ThreadSignalEvent, 0, FALSE);\r
+  }\r
+  KeReleaseSpinLock(&SpinLock, Irql);\r
+\r
+  if (RtlCompareMemory(Tag->DeviceExtension->Disk.ServerMac, "\xff\xff\xff\xff\xff\xff", 6) == 6) {\r
+    RtlCopyMemory(Tag->DeviceExtension->Disk.ServerMac, SourceMac, 6);\r
+    DbgPrint("Major: %d minor: %d found on server %02x:%02x:%02x:%02x:%02x:%02x\n", Tag->DeviceExtension->Disk.Major, Tag->DeviceExtension->Disk.Minor, SourceMac[0], SourceMac[1], SourceMac[2], SourceMac[3], SourceMac[4], SourceMac[5]);\r
+  }\r
+\r
+  KeQuerySystemTime(&CurrentTime);\r
+  Tag->DeviceExtension->Disk.Timeout -= (ULONG)((Tag->DeviceExtension->Disk.Timeout - (CurrentTime.QuadPart - Tag->FirstSendTime.QuadPart)) / 1024);\r
+  if (Tag->DeviceExtension->Disk.Timeout > 100000000) Tag->DeviceExtension->Disk.Timeout = 100000000;\r
+\r
+  switch (Tag->Type) {\r
+    case SearchDriveType:\r
+      KeAcquireSpinLock(&Tag->DeviceExtension->Disk.SpinLock, &Irql);\r
+      switch (Tag->DeviceExtension->Disk.SearchState) {\r
+        case GettingSize:\r
+          RtlCopyMemory(&Tag->DeviceExtension->Disk.LBADiskSize, &Reply->Data[200], sizeof(LONGLONG));\r
+          Tag->DeviceExtension->Disk.SearchState = GetGeometry;\r
+          break;\r
+        case GettingGeometry:\r
+          Tag->DeviceExtension->Disk.Heads = 255;       // FIXME use real values from partition table\r
+          Tag->DeviceExtension->Disk.Sectors = 63;\r
+          Tag->DeviceExtension->Disk.Cylinders = Tag->DeviceExtension->Disk.LBADiskSize / (Tag->DeviceExtension->Disk.Heads * Tag->DeviceExtension->Disk.Sectors);\r
+          Tag->DeviceExtension->Disk.LBADiskSize = Tag->DeviceExtension->Disk.Cylinders * Tag->DeviceExtension->Disk.Heads * Tag->DeviceExtension->Disk.Sectors;\r
+          Tag->DeviceExtension->Disk.SearchState = GetMaxSectorsPerPacket;\r
+          break;\r
+        case GettingMaxSectorsPerPacket:\r
+          DataSize -= sizeof(AOE);\r
+          if (DataSize < (Tag->DeviceExtension->Disk.MaxSectorsPerPacket * SECTORSIZE)) {\r
+            DbgPrint("AoEReply Packet size too low while getting MaxSectorsPerPacket (tried %d, got size of %d)\n", Tag->DeviceExtension->Disk.MaxSectorsPerPacket, DataSize);\r
+            Tag->DeviceExtension->Disk.MaxSectorsPerPacket--;\r
+            Tag->DeviceExtension->Disk.SearchState = Done;\r
+          } else if (Tag->DeviceExtension->Disk.MTU < (sizeof(AOE) + ((Tag->DeviceExtension->Disk.MaxSectorsPerPacket + 1) * SECTORSIZE))) {\r
+            DbgPrint("AoEReply Got MaxSectorsPerPacket %d at size of %d. MTU of %d reached\n", Tag->DeviceExtension->Disk.MaxSectorsPerPacket, DataSize, Tag->DeviceExtension->Disk.MTU);\r
+            Tag->DeviceExtension->Disk.SearchState = Done;\r
+          } else {\r
+            DbgPrint("AoEReply Got MaxSectorsPerPacket %d at size of %d, trying next...\n", Tag->DeviceExtension->Disk.MaxSectorsPerPacket, DataSize);\r
+            Tag->DeviceExtension->Disk.SearchState = GetMaxSectorsPerPacket;\r
+          }\r
+          break;\r
+        default:\r
+          DbgPrint("AoEReply Undefined SearchState!\n");\r
+          break;\r
+      }\r
+      KeReleaseSpinLock(&Tag->DeviceExtension->Disk.SpinLock, Irql);\r
+      KeSetEvent(&Tag->DeviceExtension->Disk.SearchEvent, 0, FALSE);\r
+      break;\r
+    case RequestType:\r
+      if (Tag->Request->Mode == Read) RtlCopyMemory(&Tag->Request->Buffer[Tag->BufferOffset], Reply->Data, Tag->SectorCount * SECTORSIZE);\r
+      if (InterlockedDecrement(&Tag->Request->TagCount) == 0) {\r
+        Tag->Request->Irp->IoStatus.Information = Tag->Request->SectorCount * SECTORSIZE;\r
+        Tag->Request->Irp->IoStatus.Status = STATUS_SUCCESS;\r
+        CompletePendingIrp(Tag->Request->Irp);\r
+        ExFreePool(Tag->Request);\r
+      }\r
+      break;\r
+    default:\r
+      DbgPrint("Unknown tag type??\n");\r
+      break;\r
+  }\r
+\r
+  KeSetEvent(&ThreadSignalEvent, 0, FALSE);\r
+  ExFreePool(Tag->PacketData);\r
+  ExFreePool(Tag);\r
+  return STATUS_SUCCESS;\r
+}\r
+\r
+VOID STDCALL AoEResetProbe() {\r
+  ProbeTag->SendTime.QuadPart = 0LL;\r
+}\r
+\r
+VOID STDCALL Thread(IN PVOID StartContext) {\r
+  LARGE_INTEGER Timeout, CurrentTime, ProbeTime, ReportTime;\r
+  ULONG NextTagId = 1;\r
+  PTAG Tag;\r
+  KIRQL Irql;\r
+  ULONG Sends = 0;\r
+  ULONG Resends = 0;\r
+  ULONG ResendFails = 0;\r
+  ULONG Fails = 0;\r
+  ULONG RequestTimeout = 0;\r
+\r
+  DbgPrint("Thread\n");\r
+  ReportTime.QuadPart = 0LL;\r
+  ProbeTime.QuadPart = 0LL;\r
+\r
+  while (TRUE) {\r
+    Timeout.QuadPart = -100000LL;               // 100.000 * 100ns = 10.000.000 ns = 10ms\r
+    KeWaitForSingleObject(&ThreadSignalEvent, Executive, KernelMode, FALSE, &Timeout);\r
+    KeResetEvent(&ThreadSignalEvent);\r
+    if (Stop) {\r
+      DbgPrint("Stopping thread...\n");\r
+      PsTerminateSystemThread(STATUS_SUCCESS);\r
+    }\r
+    BusCleanupTargetList();\r
+\r
+    KeQuerySystemTime(&CurrentTime);\r
+    if (CurrentTime.QuadPart > (ReportTime.QuadPart + 10000000LL)) {\r
+//      DbgPrint("Sends: %d  Resends: %d  ResendFails: %d  Fails: %d  OutstandingTags: %d  RequestTimeout: %d\n", Sends, Resends, ResendFails, Fails, OutstandingTags, RequestTimeout);\r
+      Sends = 0;\r
+      Resends = 0;\r
+      ResendFails = 0;\r
+      Fails = 0;\r
+      KeQuerySystemTime(&ReportTime);\r
+    }\r
+\r
+    if (CurrentTime.QuadPart > (ProbeTag->SendTime.QuadPart + 100000000LL)) {\r
+      ProbeTag->Id = NextTagId++;\r
+      if (NextTagId == 0) NextTagId++;\r
+      ProbeTag->PacketData->Tag = ProbeTag->Id;\r
+      ProtocolSend("\xff\xff\xff\xff\xff\xff", "\xff\xff\xff\xff\xff\xff", (PUCHAR)ProbeTag->PacketData, ProbeTag->PacketSize, NULL);\r
+      KeQuerySystemTime(&ProbeTag->SendTime);\r
+    }\r
+\r
+    KeAcquireSpinLock(&SpinLock, &Irql);\r
+    if (TagList == NULL) {\r
+      KeReleaseSpinLock(&SpinLock, Irql);\r
+      continue;\r
+    }\r
+    Tag = TagList;\r
+    while (Tag != NULL) {\r
+      RequestTimeout = Tag->DeviceExtension->Disk.Timeout;\r
+      if (Tag->Id == 0) {\r
+        if (OutstandingTags <= 64) {\r
+        //if (OutstandingTags <= 102400) {\r
+          if (OutstandingTags < 0) DbgPrint("!!OutstandingTags < 0 (Thread)!!\n");\r
+          Tag->Id = NextTagId++;\r
+          if (NextTagId == 0) NextTagId++;\r
+          Tag->PacketData->Tag = Tag->Id;\r
+          if (ProtocolSend(Tag->DeviceExtension->Disk.ClientMac, Tag->DeviceExtension->Disk.ServerMac, (PUCHAR)Tag->PacketData, Tag->PacketSize, Tag)) {\r
+            KeQuerySystemTime(&Tag->FirstSendTime);\r
+            KeQuerySystemTime(&Tag->SendTime);\r
+            OutstandingTags++;\r
+           Sends++;\r
+          } else {\r
+            Fails++;\r
+            Tag->Id = 0;\r
+            break;\r
+          }\r
+        }\r
+      } else {\r
+        KeQuerySystemTime(&CurrentTime);\r
+        if (CurrentTime.QuadPart > (Tag->SendTime.QuadPart + (LONGLONG)(Tag->DeviceExtension->Disk.Timeout * 2))) {\r
+          if (ProtocolSend(Tag->DeviceExtension->Disk.ClientMac, Tag->DeviceExtension->Disk.ServerMac, (PUCHAR)Tag->PacketData, Tag->PacketSize, Tag)) {\r
+            KeQuerySystemTime(&Tag->SendTime);\r
+            Tag->DeviceExtension->Disk.Timeout += Tag->DeviceExtension->Disk.Timeout / 1000;\r
+            if (Tag->DeviceExtension->Disk.Timeout > 100000000) Tag->DeviceExtension->Disk.Timeout = 100000000;\r
+            Resends++;\r
+          } else {\r
+            ResendFails++;\r
+            break;\r
+          }\r
+        }\r
+      }\r
+      Tag = Tag->Next;\r
+      if (Tag == TagList) {\r
+        DbgPrint("!!Taglist Cyclic!!\n");\r
+        break;\r
+      }\r
+    }\r
+    KeReleaseSpinLock(&SpinLock, Irql);\r
+  }\r
+}\r
diff --git a/src/aoe.h b/src/aoe.h
new file mode 100644 (file)
index 0000000..d69fbda
--- /dev/null
+++ b/src/aoe.h
@@ -0,0 +1,36 @@
+/*\r
+  Copyright 2006-2008, V.\r
+  For contact information, see http://winaoe.org/\r
+\r
+  This file is part of WinAoE.\r
+\r
+  WinAoE is free software: you can redistribute it and/or modify\r
+  it under the terms of the GNU General Public License as published by\r
+  the Free Software Foundation, either version 3 of the License, or\r
+  (at your option) any later version.\r
+\r
+  WinAoE is distributed in the hope that it will be useful,\r
+  but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+  GNU General Public License for more details.\r
+\r
+  You should have received a copy of the GNU General Public License\r
+  along with WinAoE.  If not, see <http://www.gnu.org/licenses/>.\r
+*/\r
+\r
+#ifndef _AOE_H\r
+#define _AOE_H\r
+#include "portable.h"\r
+#include "driver.h"\r
+\r
+#define htons(x) (USHORT)((((x) << 8) & 0xff00) | (((x) >> 8) & 0xff))\r
+#define ntohs(x) (USHORT)((((x) << 8) & 0xff00) | (((x) >> 8) & 0xff))\r
+\r
+typedef enum {Read, Write} REQUESTMODE, *PREQUESTMODE;\r
+\r
+BOOLEAN STDCALL AoESearchDrive(IN PDEVICEEXTENSION DeviceExtension);\r
+NTSTATUS STDCALL AoERequest(IN PDEVICEEXTENSION DeviceExtension, IN REQUESTMODE Mode, IN LONGLONG StartSector, IN ULONG SectorCount, IN PUCHAR Buffer, IN PIRP Irp);\r
+NTSTATUS STDCALL AoEReply(IN PUCHAR SourceMac, IN PUCHAR DestinationMac, IN PUCHAR Data, IN UINT DataSize);\r
+VOID STDCALL AoEResetProbe();\r
+\r
+#endif\r
diff --git a/src/bus.c b/src/bus.c
new file mode 100644 (file)
index 0000000..f027d25
--- /dev/null
+++ b/src/bus.c
@@ -0,0 +1,515 @@
+/*\r
+  Copyright 2006-2008, V.\r
+  For contact information, see http://winaoe.org/\r
+\r
+  This file is part of WinAoE.\r
+\r
+  WinAoE is free software: you can redistribute it and/or modify\r
+  it under the terms of the GNU General Public License as published by\r
+  the Free Software Foundation, either version 3 of the License, or\r
+  (at your option) any later version.\r
+\r
+  WinAoE is distributed in the hope that it will be useful,\r
+  but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+  GNU General Public License for more details.\r
+\r
+  You should have received a copy of the GNU General Public License\r
+  along with WinAoE.  If not, see <http://www.gnu.org/licenses/>.\r
+*/\r
+\r
+#include "portable.h"\r
+#include <ntddk.h>\r
+#include "driver.h"\r
+#include "aoe.h"\r
+#include "mount.h"\r
+\r
+// in this file\r
+BOOLEAN STDCALL BusAddChild(IN PDEVICE_OBJECT BusDeviceObject, IN PUCHAR ClientMac, IN ULONG Major, IN ULONG Minor, IN BOOLEAN Boot);\r
+NTSTATUS STDCALL IoCompletionRoutine(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PKEVENT Event);\r
+\r
+#ifdef _MSC_VER\r
+#pragma pack(1)\r
+#endif\r
+typedef struct _ABFT {\r
+  UINT Signature;               // 0x54464261 (aBFT)\r
+  UINT Length;\r
+  UCHAR Revision;\r
+  UCHAR Checksum;\r
+  UCHAR OEMID[6];\r
+  UCHAR OEMTableID[8];\r
+  UCHAR Reserved1[12];\r
+  USHORT Major;\r
+  UCHAR Minor;\r
+  UCHAR Reserved2;\r
+  UCHAR ClientMac[6];\r
+} __attribute__((__packed__)) ABFT, *PABFT;\r
+#ifdef _MSC_VER\r
+#pragma pack()\r
+#endif\r
+\r
+typedef struct _TARGETLIST {\r
+  TARGET Target;\r
+  struct _TARGETLIST *Next;\r
+} TARGETLIST, *PTARGETLIST;\r
+\r
+PTARGETLIST TargetList = NULL;\r
+KSPIN_LOCK TargetListSpinLock;\r
+ULONG NextDisk = 0;\r
+\r
+NTSTATUS STDCALL BusStart() {\r
+  DbgPrint("BusStart\n");\r
+  KeInitializeSpinLock(&TargetListSpinLock);\r
+  return STATUS_SUCCESS;\r
+}\r
+\r
+VOID STDCALL BusStop() {\r
+  UNICODE_STRING DosDeviceName;\r
+  PTARGETLIST Walker, Next;\r
+  KIRQL Irql;\r
+\r
+  DbgPrint("BusStop\n");\r
+  KeAcquireSpinLock(&TargetListSpinLock, &Irql);\r
+  Walker = TargetList;\r
+  while (Walker != NULL) {\r
+    Next = Walker->Next;\r
+    ExFreePool(Walker);\r
+    Walker = Next;\r
+  }\r
+  KeReleaseSpinLock(&TargetListSpinLock, Irql);\r
+  RtlInitUnicodeString(&DosDeviceName, L"\\DosDevices\\AoE");\r
+  IoDeleteSymbolicLink(&DosDeviceName);\r
+}\r
+\r
+NTSTATUS STDCALL BusAddDevice(IN PDRIVER_OBJECT DriverObject, IN PDEVICE_OBJECT PhysicalDeviceObject) {\r
+  NTSTATUS Status;\r
+  PHYSICAL_ADDRESS PhysicalAddress;\r
+  PUCHAR PhysicalMemory;\r
+  UINT Offset, Checksum, i;\r
+  ABFT AOEBootRecord;\r
+  BOOLEAN FoundAbft = FALSE;\r
+  UNICODE_STRING DeviceName, DosDeviceName;\r
+  PDEVICEEXTENSION DeviceExtension;\r
+  PDEVICE_OBJECT DeviceObject;\r
+\r
+  DbgPrint("BusAddDevice\n");\r
+  RtlInitUnicodeString(&DeviceName, L"\\Device\\AoE");\r
+  RtlInitUnicodeString(&DosDeviceName, L"\\DosDevices\\AoE");\r
+  if (!NT_SUCCESS(Status = IoCreateDevice(DriverObject, sizeof(DEVICEEXTENSION), &DeviceName, FILE_DEVICE_CONTROLLER, FILE_DEVICE_SECURE_OPEN, FALSE, &DeviceObject))) {\r
+    return Error("BusAddDevice IoCreateDevice", Status);\r
+  }\r
+  if (!NT_SUCCESS(Status = IoCreateSymbolicLink(&DosDeviceName, &DeviceName))) {\r
+    IoDeleteDevice(DeviceObject);\r
+    return Error("BusAddDevice IoCreateSymbolicLink", Status);\r
+  }\r
+\r
+  DeviceExtension = (PDEVICEEXTENSION)DeviceObject->DeviceExtension;\r
+  RtlZeroMemory(DeviceExtension, sizeof(DEVICEEXTENSION));\r
+  DeviceExtension->IsBus = TRUE;\r
+  DeviceExtension->DriverObject = DriverObject;\r
+  DeviceExtension->Self = DeviceObject;\r
+  DeviceExtension->State = NotStarted;\r
+  DeviceExtension->OldState = NotStarted;\r
+  DeviceExtension->Bus.PhysicalDeviceObject = PhysicalDeviceObject;\r
+  DeviceExtension->Bus.Children = 0;\r
+  DeviceExtension->Bus.ChildList = NULL;\r
+  KeInitializeSpinLock(&DeviceExtension->Bus.SpinLock);\r
+  DeviceObject->Flags |= DO_DIRECT_IO;                  // FIXME?\r
+  DeviceObject->Flags |= DO_POWER_INRUSH;               // FIXME?\r
+  if (PhysicalDeviceObject != NULL) {\r
+    if ((DeviceExtension->Bus.LowerDeviceObject = IoAttachDeviceToDeviceStack(DeviceObject, PhysicalDeviceObject)) == NULL) {\r
+      IoDeleteDevice(DeviceObject);\r
+      return Error("AddDevice IoAttachDeviceToDeviceStack", STATUS_NO_SUCH_DEVICE);\r
+    }\r
+  }\r
+  DeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;\r
+\r
+  PhysicalAddress.QuadPart = 0LL;\r
+  PhysicalMemory = MmMapIoSpace(PhysicalAddress, 0xa0000, MmNonCached);\r
+  if (!PhysicalMemory) {\r
+    DbgPrint("Could not map low memory\n");\r
+  } else {\r
+    for (Offset = 0; Offset < 0xa0000; Offset += 0x10) {\r
+      if (((PABFT)&PhysicalMemory[Offset])->Signature == 0x54464261) {\r
+        Checksum = 0;\r
+        for (i = 0; i < ((PABFT)&PhysicalMemory[Offset])->Length; i++) Checksum += PhysicalMemory[Offset + i];\r
+        if (Checksum & 0xff) continue;\r
+        if (((PABFT)&PhysicalMemory[Offset])->Revision != 1) {\r
+          DbgPrint("Found aBFT with mismatched revision v%d at segment 0x%4x. want v1.\n", ((PABFT)&PhysicalMemory[Offset])->Revision, (Offset / 0x10));\r
+          continue;\r
+        }\r
+        DbgPrint("Found aBFT at segment: 0x%04x\n", (Offset / 0x10));\r
+        RtlCopyMemory(&AOEBootRecord, &PhysicalMemory[Offset], sizeof(ABFT));\r
+        FoundAbft = TRUE;\r
+        break;\r
+      }\r
+    }\r
+    MmUnmapIoSpace(PhysicalMemory, 0xa0000);\r
+  }\r
+\r
+#ifdef RIS\r
+  FoundAbft = TRUE;\r
+  RtlCopyMemory(AOEBootRecord.ClientMac, "\x00\x0c\x29\x34\x69\x34", 6);\r
+  AOEBootRecord.Major = 0;\r
+  AOEBootRecord.Minor = 10;\r
+#endif\r
+\r
+  if (FoundAbft) {\r
+    DbgPrint("Boot from client NIC %02x:%02x:%02x:%02x:%02x:%02x to major: %d minor: %d\n", AOEBootRecord.ClientMac[0], AOEBootRecord.ClientMac[1], AOEBootRecord.ClientMac[2], AOEBootRecord.ClientMac[3], AOEBootRecord.ClientMac[4], AOEBootRecord.ClientMac[5], AOEBootRecord.Major, AOEBootRecord.Minor);\r
+    if (!BusAddChild(DeviceObject, AOEBootRecord.ClientMac, AOEBootRecord.Major, AOEBootRecord.Minor, TRUE)) {\r
+      DbgPrint("BusAddChild failed\n");\r
+    } else {\r
+      if (DeviceExtension->Bus.PhysicalDeviceObject != NULL) IoInvalidateDeviceRelations(DeviceExtension->Bus.PhysicalDeviceObject, BusRelations);\r
+    }\r
+  } else {\r
+    DbgPrint("Not booting...\n");\r
+  }\r
+#ifdef RIS\r
+  DeviceExtension->State = Started;\r
+#endif\r
+  return STATUS_SUCCESS;\r
+}\r
+\r
+VOID STDCALL BusAddTarget(IN PUCHAR ClientMac, IN PUCHAR ServerMac, USHORT Major, UCHAR Minor, LONGLONG LBASize) {\r
+  PTARGETLIST Walker, Last;\r
+  KIRQL Irql;\r
+\r
+  KeAcquireSpinLock(&TargetListSpinLock, &Irql);\r
+  Last = TargetList;\r
+  Walker = TargetList;\r
+  while (Walker != NULL) {\r
+    if ((RtlCompareMemory(&Walker->Target.ClientMac, ClientMac, 6) == 6) && (RtlCompareMemory(&Walker->Target.ServerMac, ServerMac, 6) == 6) && Walker->Target.Major == Major && Walker->Target.Minor == Minor) {\r
+      if (Walker->Target.LBASize != LBASize) {\r
+        DbgPrint("BusAddTarget LBASize changed for e%d.%d (%I64u->%I64u)\n", Major, Minor, Walker->Target.LBASize, LBASize);\r
+        Walker->Target.LBASize = LBASize;\r
+      }\r
+      KeQuerySystemTime(&Walker->Target.ProbeTime);\r
+      KeReleaseSpinLock(&TargetListSpinLock, Irql);\r
+      return;\r
+    }\r
+    Last = Walker;\r
+    Walker = Walker->Next;\r
+  }\r
+\r
+  if ((Walker = (PTARGETLIST)ExAllocatePool(NonPagedPool, sizeof(TARGETLIST))) == NULL) {\r
+    DbgPrint("BusAddTarget ExAllocatePool Target\n");\r
+    KeReleaseSpinLock(&TargetListSpinLock, Irql);\r
+    return;\r
+  }\r
+  Walker->Next = NULL;\r
+  RtlCopyMemory(Walker->Target.ClientMac, ClientMac, 6);\r
+  RtlCopyMemory(Walker->Target.ServerMac, ServerMac, 6);\r
+  Walker->Target.Major = Major;\r
+  Walker->Target.Minor = Minor;\r
+  Walker->Target.LBASize = LBASize;\r
+  KeQuerySystemTime(&Walker->Target.ProbeTime);\r
+\r
+  if (Last == NULL) {\r
+    TargetList = Walker;\r
+  } else {\r
+    Last->Next = Walker;\r
+  }\r
+  KeReleaseSpinLock(&TargetListSpinLock, Irql);\r
+}\r
+\r
+VOID STDCALL BusCleanupTargetList() {\r
+}\r
+\r
+BOOLEAN STDCALL BusAddChild(IN PDEVICE_OBJECT BusDeviceObject, IN PUCHAR ClientMac, IN ULONG Major, IN ULONG Minor, IN BOOLEAN Boot) {\r
+  NTSTATUS Status;\r
+  PDEVICEEXTENSION BusDeviceExtension = (PDEVICEEXTENSION)BusDeviceObject->DeviceExtension;\r
+  PDEVICE_OBJECT DeviceObject;\r
+  PDEVICEEXTENSION DeviceExtension, Walker;\r
+\r
+  DbgPrint("BusAddChild\n");\r
+  if (!NT_SUCCESS(Status = IoCreateDevice(BusDeviceExtension->DriverObject, sizeof(DEVICEEXTENSION), NULL, FILE_DEVICE_DISK, FILE_AUTOGENERATED_DEVICE_NAME | FILE_DEVICE_SECURE_OPEN, FALSE, &DeviceObject))) {\r
+    Error("BusAddChild IoCreateDevice", Status);\r
+    return FALSE;\r
+  }\r
+  DeviceExtension = (PDEVICEEXTENSION)DeviceObject->DeviceExtension;\r
+  RtlZeroMemory(DeviceExtension, sizeof(DEVICEEXTENSION));\r
+\r
+  DeviceExtension->IsBus = FALSE;\r
+  DeviceExtension->Self = DeviceObject;\r
+  DeviceExtension->DriverObject = BusDeviceExtension->DriverObject;\r
+  DeviceExtension->State = NotStarted;\r
+  DeviceExtension->OldState = NotStarted;\r
+\r
+  DeviceExtension->Disk.Parent = BusDeviceObject;\r
+  DeviceExtension->Disk.Next = NULL;\r
+  KeInitializeEvent(&DeviceExtension->Disk.SearchEvent, SynchronizationEvent, FALSE);\r
+  KeInitializeSpinLock(&DeviceExtension->Disk.SpinLock);\r
+  DeviceExtension->Disk.BootDrive = Boot;\r
+  DeviceExtension->Disk.Unmount = FALSE;\r
+  DeviceExtension->Disk.DiskNumber = InterlockedIncrement(&NextDisk) - 1;\r
+  RtlCopyMemory(DeviceExtension->Disk.ClientMac, ClientMac, 6);\r
+  RtlFillMemory(DeviceExtension->Disk.ServerMac, 6, 0xff);\r
+  DeviceExtension->Disk.Major = Major;\r
+  DeviceExtension->Disk.Minor = Minor;\r
+  DeviceExtension->Disk.MaxSectorsPerPacket = 1;\r
+  DeviceExtension->Disk.Timeout = 200000;               // 20 ms.\r
+\r
+  DeviceObject->Flags |= DO_DIRECT_IO;                  // FIXME?\r
+  DeviceObject->Flags |= DO_POWER_INRUSH;               // FIXME?\r
+  AoESearchDrive(DeviceExtension);\r
+  DeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;\r
+  if (BusDeviceExtension->Bus.ChildList == NULL) {\r
+    BusDeviceExtension->Bus.ChildList = DeviceExtension;\r
+  } else {\r
+    Walker = BusDeviceExtension->Bus.ChildList;\r
+    while (Walker->Disk.Next != NULL) Walker = Walker->Disk.Next;\r
+    Walker->Disk.Next = DeviceExtension;\r
+  }\r
+  BusDeviceExtension->Bus.Children++;\r
+  return TRUE;\r
+}\r
+\r
+NTSTATUS STDCALL BusDispatchPnP(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PIO_STACK_LOCATION Stack, IN PDEVICEEXTENSION DeviceExtension) {\r
+  NTSTATUS Status;\r
+  KEVENT Event;\r
+  PDEVICE_RELATIONS DeviceRelations;\r
+  PDEVICEEXTENSION Walker, Next;\r
+  ULONG Count;\r
+\r
+  switch (Stack->MinorFunction) {\r
+    case IRP_MN_START_DEVICE:\r
+      KeInitializeEvent(&Event, NotificationEvent, FALSE);\r
+      IoCopyCurrentIrpStackLocationToNext(Irp);\r
+      IoSetCompletionRoutine(Irp, (PIO_COMPLETION_ROUTINE)IoCompletionRoutine, (PVOID)&Event, TRUE, TRUE, TRUE);\r
+      Status = IoCallDriver(DeviceExtension->Bus.LowerDeviceObject, Irp);\r
+      if (Status == STATUS_PENDING) {\r
+        DbgPrint("Locked\n");\r
+        KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);\r
+      }\r
+      if (NT_SUCCESS(Status = Irp->IoStatus.Status)) {\r
+        DeviceExtension->OldState = DeviceExtension->State;\r
+        DeviceExtension->State = Started;\r
+      }\r
+      Status = STATUS_SUCCESS;\r
+      Irp->IoStatus.Status = Status;\r
+      IoCompleteRequest(Irp, IO_NO_INCREMENT);\r
+      return Status;\r
+    case IRP_MN_REMOVE_DEVICE:\r
+      DeviceExtension->OldState = DeviceExtension->State;\r
+      DeviceExtension->State = Deleted;\r
+      Irp->IoStatus.Information = 0;\r
+      Irp->IoStatus.Status = STATUS_SUCCESS;\r
+      IoSkipCurrentIrpStackLocation(Irp);\r
+      Status = IoCallDriver(DeviceExtension->Bus.LowerDeviceObject, Irp);\r
+      Walker = DeviceExtension->Bus.ChildList;\r
+      while (Walker != NULL) {\r
+        Next = Walker->Disk.Next;\r
+        IoDeleteDevice(Walker->Self);\r
+        Walker = Next;\r
+      }\r
+      DeviceExtension->Bus.Children = 0;\r
+      DeviceExtension->Bus.ChildList = NULL;\r
+      IoDetachDevice(DeviceExtension->Bus.LowerDeviceObject);\r
+      IoDeleteDevice(DeviceExtension->Self);\r
+      return Status;\r
+    case IRP_MN_QUERY_DEVICE_RELATIONS:\r
+      if (Stack->Parameters.QueryDeviceRelations.Type != BusRelations || Irp->IoStatus.Information) {\r
+        Status = Irp->IoStatus.Status;\r
+        break;\r
+      }\r
+      Count = 0;\r
+      Walker = DeviceExtension->Bus.ChildList;\r
+      while (Walker != NULL) {\r
+        Count++;\r
+        Walker = Walker->Disk.Next;\r
+      }\r
+\r
+      if ((DeviceRelations = (PDEVICE_RELATIONS)ExAllocatePool(NonPagedPool, sizeof(DEVICE_RELATIONS) + (sizeof(PDEVICE_OBJECT) * Count))) == NULL) {\r
+        Irp->IoStatus.Information = 0;\r
+        Status = STATUS_INSUFFICIENT_RESOURCES;\r
+        break;\r
+      }\r
+      DeviceRelations->Count = Count;\r
+\r
+      Count = 0;\r
+      Walker = DeviceExtension->Bus.ChildList;\r
+      while (Walker != NULL) {\r
+        DeviceRelations->Objects[Count] = Walker->Self;\r
+        Count++;\r
+        Walker = Walker->Disk.Next;\r
+      }\r
+      Irp->IoStatus.Information = (ULONG_PTR)DeviceRelations;\r
+      Status = STATUS_SUCCESS;\r
+      break;\r
+    case IRP_MN_QUERY_PNP_DEVICE_STATE:\r
+      Irp->IoStatus.Information = 0;\r
+      Status = STATUS_SUCCESS;\r
+      break;\r
+    case IRP_MN_QUERY_STOP_DEVICE:\r
+      DeviceExtension->OldState = DeviceExtension->State;\r
+      DeviceExtension->State = StopPending;\r
+      Status = STATUS_SUCCESS;\r
+      break;\r
+    case IRP_MN_CANCEL_STOP_DEVICE:\r
+      DeviceExtension->State = DeviceExtension->OldState;\r
+      Status = STATUS_SUCCESS;\r
+      break;\r
+    case IRP_MN_STOP_DEVICE:\r
+      DeviceExtension->OldState = DeviceExtension->State;\r
+      DeviceExtension->State = Stopped;\r
+      Status = STATUS_SUCCESS;\r
+      break;\r
+    case IRP_MN_QUERY_REMOVE_DEVICE:\r
+      DeviceExtension->OldState = DeviceExtension->State;\r
+      DeviceExtension->State = RemovePending;\r
+      Status = STATUS_SUCCESS;\r
+      break;\r
+    case IRP_MN_CANCEL_REMOVE_DEVICE:\r
+      DeviceExtension->State = DeviceExtension->OldState;\r
+      Status = STATUS_SUCCESS;\r
+      break;\r
+    case IRP_MN_SURPRISE_REMOVAL:\r
+      DeviceExtension->OldState = DeviceExtension->State;\r
+      DeviceExtension->State = SurpriseRemovePending;\r
+      Status = STATUS_SUCCESS;\r
+      break;\r
+    default:\r
+      Status = Irp->IoStatus.Status;\r
+  }\r
+\r
+  Irp->IoStatus.Status = Status;\r
+  IoSkipCurrentIrpStackLocation(Irp);\r
+  Status = IoCallDriver(DeviceExtension->Bus.LowerDeviceObject, Irp);\r
+  return Status;\r
+}\r
+\r
+NTSTATUS STDCALL BusDispatchDeviceControl(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PIO_STACK_LOCATION Stack, IN PDEVICEEXTENSION DeviceExtension) {\r
+  NTSTATUS Status;\r
+  PUCHAR Buffer;\r
+  ULONG Count;\r
+  PTARGETLIST TargetWalker;\r
+  PDEVICEEXTENSION DiskWalker, DiskWalkerPrevious;\r
+  PTARGETS Targets;\r
+  PDISKS Disks;\r
+  KIRQL Irql;\r
+\r
+  switch (Stack->Parameters.DeviceIoControl.IoControlCode) {\r
+    case IOCTL_AOE_SCAN:\r
+      DbgPrint("Got IOCTL_AOE_SCAN...\n");\r
+      KeAcquireSpinLock(&TargetListSpinLock, &Irql);\r
+\r
+      Count = 0;\r
+      TargetWalker = TargetList;\r
+      while (TargetWalker != NULL) {\r
+        Count++;\r
+        TargetWalker = TargetWalker->Next;\r
+      }\r
+\r
+      if ((Targets = (PTARGETS)ExAllocatePool(NonPagedPool, sizeof(TARGETS) + (Count * sizeof(TARGET)))) == NULL) {\r
+        DbgPrint("BusDispatchDeviceControl ExAllocatePool Targets\n");\r
+        Irp->IoStatus.Information = 0;\r
+        Status = STATUS_INSUFFICIENT_RESOURCES;\r
+        break;\r
+      }\r
+      Irp->IoStatus.Information = sizeof(TARGETS) + (Count * sizeof(TARGET));\r
+      Targets->Count = Count;\r
+\r
+      Count = 0;\r
+      TargetWalker = TargetList;\r
+      while (TargetWalker != NULL) {\r
+        RtlCopyMemory(&Targets->Target[Count], &TargetWalker->Target, sizeof(TARGET));\r
+        Count++;\r
+        TargetWalker = TargetWalker->Next;\r
+      }\r
+      RtlCopyMemory(Irp->AssociatedIrp.SystemBuffer, Targets, (Stack->Parameters.DeviceIoControl.OutputBufferLength < (sizeof(TARGETS) + (Count * sizeof(TARGET)))?Stack->Parameters.DeviceIoControl.OutputBufferLength:(sizeof(TARGETS) + (Count * sizeof(TARGET)))));\r
+      ExFreePool(Targets);\r
+\r
+      KeReleaseSpinLock(&TargetListSpinLock, Irql);\r
+      Status = STATUS_SUCCESS;\r
+      break;\r
+    case IOCTL_AOE_SHOW:\r
+      DbgPrint("Got IOCTL_AOE_SHOW...\n");\r
+\r
+      Count = 0;\r
+      DiskWalker = DeviceExtension->Bus.ChildList;\r
+      while (DiskWalker != NULL) {\r
+        Count++;\r
+        DiskWalker = DiskWalker->Disk.Next;\r
+      }\r
+\r
+      if ((Disks = (PDISKS)ExAllocatePool(NonPagedPool, sizeof(DISKS) + (Count * sizeof(DISK)))) == NULL) {\r
+        DbgPrint("BusDispatchDeviceControl ExAllocatePool Disks\n");\r
+        Irp->IoStatus.Information = 0;\r
+        Status = STATUS_INSUFFICIENT_RESOURCES;\r
+        break;\r
+      }\r
+      Irp->IoStatus.Information = sizeof(DISKS) + (Count * sizeof(DISK));\r
+      Disks->Count = Count;\r
+\r
+      Count = 0;\r
+      DiskWalker = DeviceExtension->Bus.ChildList;\r
+      while (DiskWalker != NULL) {\r
+        Disks->Disk[Count].Disk = DiskWalker->Disk.DiskNumber;\r
+        RtlCopyMemory(&Disks->Disk[Count].ClientMac, &DiskWalker->Disk.ClientMac, 6);\r
+        RtlCopyMemory(&Disks->Disk[Count].ServerMac, &DiskWalker->Disk.ServerMac, 6);\r
+        Disks->Disk[Count].Major = DiskWalker->Disk.Major;\r
+        Disks->Disk[Count].Minor = DiskWalker->Disk.Minor;\r
+        Disks->Disk[Count].LBASize = DiskWalker->Disk.LBADiskSize;\r
+        Count++;\r
+        DiskWalker = DiskWalker->Disk.Next;\r
+      }\r
+      RtlCopyMemory(Irp->AssociatedIrp.SystemBuffer, Disks, (Stack->Parameters.DeviceIoControl.OutputBufferLength < (sizeof(DISKS) + (Count * sizeof(DISK)))?Stack->Parameters.DeviceIoControl.OutputBufferLength:(sizeof(DISKS) + (Count * sizeof(DISK)))));\r
+      ExFreePool(Disks);\r
+\r
+      Status = STATUS_SUCCESS;\r
+      break;\r
+    case IOCTL_AOE_MOUNT:\r
+      Buffer = Irp->AssociatedIrp.SystemBuffer;\r
+      DbgPrint("Got IOCTL_AOE_MOUNT for client: %02x:%02x:%02x:%02x:%02x:%02x Major:%d Minor:%d\n", Buffer[0], Buffer[1], Buffer[2], Buffer[3], Buffer[4], Buffer[5], *(PUSHORT)(&Buffer[6]), (UCHAR)Buffer[8]);\r
+      if (!BusAddChild(DeviceObject, Buffer, *(PUSHORT)(&Buffer[6]), (UCHAR)Buffer[8], FALSE)) {\r
+        DbgPrint("BusAddChild failed\n");\r
+      } else {\r
+        if (DeviceExtension->Bus.PhysicalDeviceObject != NULL) IoInvalidateDeviceRelations(DeviceExtension->Bus.PhysicalDeviceObject, BusRelations);\r
+      }\r
+      Irp->IoStatus.Information = 0;\r
+      Status = STATUS_SUCCESS;\r
+      break;\r
+    case IOCTL_AOE_UMOUNT:\r
+      Buffer = Irp->AssociatedIrp.SystemBuffer;\r
+      DbgPrint("Got IOCTL_AOE_UMOUNT for disk: %d\n", *(PULONG)Buffer);\r
+      DiskWalker = DeviceExtension->Bus.ChildList;\r
+      DiskWalkerPrevious = DiskWalker;\r
+      while ((DiskWalker != NULL) && (!DiskWalker->Disk.BootDrive) && (DiskWalker->Disk.DiskNumber != *(PULONG)Buffer)) {\r
+        DiskWalkerPrevious = DiskWalker;\r
+        DiskWalker = DiskWalker->Disk.Next;\r
+      }\r
+      if (DiskWalker != NULL) {\r
+        DbgPrint("Deleting disk %d\n", DiskWalker->Disk.DiskNumber);\r
+        if (DiskWalker == DeviceExtension->Bus.ChildList) {\r
+          DeviceExtension->Bus.ChildList = DiskWalker->Disk.Next;\r
+        } else {\r
+          DiskWalkerPrevious->Disk.Next = DiskWalker->Disk.Next;\r
+        }\r
+        DiskWalker->Disk.Unmount = TRUE;\r
+        DiskWalker->Disk.Next = NULL;\r
+        if (DeviceExtension->Bus.PhysicalDeviceObject != NULL) IoInvalidateDeviceRelations(DeviceExtension->Bus.PhysicalDeviceObject, BusRelations);\r
+      }\r
+      DeviceExtension->Bus.Children--;\r
+      Irp->IoStatus.Information = 0;\r
+      Status = STATUS_SUCCESS;\r
+      break;\r
+    default:\r
+      Irp->IoStatus.Information = 0;\r
+      Status = STATUS_INVALID_DEVICE_REQUEST;\r
+  }\r
+\r
+  Irp->IoStatus.Status = Status;\r
+  IoCompleteRequest(Irp, IO_NO_INCREMENT);\r
+  return Status;\r
+}\r
+\r
+NTSTATUS STDCALL BusDispatchSystemControl(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PIO_STACK_LOCATION Stack, IN PDEVICEEXTENSION DeviceExtension) {\r
+  DbgPrint("...\n");\r
+  IoSkipCurrentIrpStackLocation(Irp);\r
+  return IoCallDriver(DeviceExtension->Bus.LowerDeviceObject, Irp);\r
+}\r
+\r
+NTSTATUS STDCALL IoCompletionRoutine(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PKEVENT Event) {\r
+  KeSetEvent(Event, 0, FALSE);\r
+  return STATUS_MORE_PROCESSING_REQUIRED;\r
+}\r
diff --git a/src/debug.c b/src/debug.c
new file mode 100644 (file)
index 0000000..c1abd38
--- /dev/null
@@ -0,0 +1,431 @@
+/*\r
+  Copyright 2006-2008, V.\r
+  For contact information, see http://winaoe.org/\r
+\r
+  This file is part of WinAoE.\r
+\r
+  WinAoE is free software: you can redistribute it and/or modify\r
+  it under the terms of the GNU General Public License as published by\r
+  the Free Software Foundation, either version 3 of the License, or\r
+  (at your option) any later version.\r
+\r
+  WinAoE is distributed in the hope that it will be useful,\r
+  but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+  GNU General Public License for more details.\r
+\r
+  You should have received a copy of the GNU General Public License\r
+  along with WinAoE.  If not, see <http://www.gnu.org/licenses/>.\r
+*/\r
+\r
+#include "portable.h"\r
+#include <ntddk.h>\r
+#include <srb.h>\r
+#include <scsi.h>\r
+#include <ntddscsi.h>\r
+#include <ntddstor.h>\r
+#include <ntdddisk.h>\r
+#include <ndis.h>\r
+#include "driver.h"\r
+#include "mount.h"\r
+\r
+typedef struct _IRPLIST {\r
+  PIRP Irp;\r
+  ULONG Number;\r
+  PCHAR DebugMessage;\r
+  struct _IRPLIST *Next;\r
+  struct _IRPLIST *Previous;\r
+} IRPLIST, *PIRPLIST;\r
+\r
+PIRPLIST IrpList = NULL;\r
+KSPIN_LOCK SpinLock;\r
+ULONG Number = 0;\r
+\r
+extern int sprintf(char*, const char *, ...);\r
+\r
+// in this file\r
+PIRPLIST STDCALL IrpListRecord(IN PIRP Irp);\r
+VOID STDCALL DecodeIrp(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PCHAR DebugMessage);\r
+PCHAR STDCALL MajorFunctionString(IN UCHAR MajorFunction);\r
+PCHAR STDCALL PnPMinorFunctionString(IN UCHAR MinorFunction);\r
+PCHAR STDCALL SystemControlMinorFunctionString(IN UCHAR MinorFunction);\r
+PCHAR STDCALL PowerMinorFunctionString(IN UCHAR MinorFunction);\r
+PCHAR STDCALL QueryDeviceRelationsString(IN DEVICE_RELATION_TYPE Type);\r
+PCHAR STDCALL QueryIdString(IN BUS_QUERY_ID_TYPE IdType);\r
+PCHAR STDCALL SrbFunctionString(IN UCHAR Function);\r
+PCHAR STDCALL DeviceIoControlString(IN ULONG IoControlCode);\r
+PCHAR STDCALL DeviceTextTypeString(IN DEVICE_TEXT_TYPE DeviceTextType);\r
+PCHAR STDCALL SCSIOPString(IN UCHAR OperationCode);\r
+\r
+VOID STDCALL InitializeDebug() {\r
+  KeInitializeSpinLock(&SpinLock);\r
+}\r
+\r
+PIRPLIST STDCALL IrpListRecord(IN PIRP Irp) {\r
+  PIRPLIST Record;\r
+  KIRQL Irql;\r
+\r
+  KeAcquireSpinLock(&SpinLock, &Irql);\r
+  Record = IrpList;\r
+  while (Record != NULL && Record->Irp != Irp) Record = Record->Next;\r
+  KeReleaseSpinLock(&SpinLock, Irql);\r
+  return Record;\r
+}\r
+\r
+VOID STDCALL DebugIrpStart(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) {\r
+  PCHAR DebugMessage;\r
+  PIRPLIST Record, Temp;\r
+  KIRQL Irql;\r
+\r
+  if ((DebugMessage = (PCHAR)ExAllocatePool(NonPagedPool, 1024)) == NULL) {\r
+    DbgPrint("DebugIrpStart ExAllocatePool DebugMessage\n");\r
+  }\r
+  DecodeIrp(DeviceObject, Irp, DebugMessage);\r
+  if ((Record = (PIRPLIST)ExAllocatePool(NonPagedPool, sizeof(IRPLIST))) == NULL) {\r
+    DbgPrint("DebugIrpStart ExAllocatePool Record\n");\r
+    DbgPrint("IRP %s\n", DebugMessage);\r
+  }\r
+  Record->Next = NULL;\r
+  Record->Previous = NULL;\r
+  Record->Irp = Irp;\r
+  Record->DebugMessage = DebugMessage;\r
+  Record->Number = InterlockedIncrement(&Number);;\r
+  KeAcquireSpinLock(&SpinLock, &Irql);\r
+  if (IrpList == NULL) {\r
+    IrpList = Record;\r
+    Record->Previous = NULL;\r
+  } else {\r
+    Temp = IrpList;\r
+    while (Temp->Next != NULL) Temp = Temp->Next;\r
+    Temp->Next = Record;\r
+    Record->Previous = Temp;\r
+  }\r
+  KeReleaseSpinLock(&SpinLock, Irql);\r
+  DbgPrint("IRP %d: %s\n", Record->Number, Record->DebugMessage);\r
+}\r
+\r
+VOID STDCALL DebugIrpEnd(IN PIRP Irp, IN NTSTATUS Status) {\r
+  PIRPLIST Record;\r
+  KIRQL Irql;\r
+\r
+  if ((Record = IrpListRecord(Irp)) == NULL) {\r
+    DbgPrint("Irp not found in IrpList!! (returned 0x%08x, Status)\n");\r
+    return;\r
+  }\r
+  // There is no race condition between getting the record and unlinking in IrpList, unless DebugIrpEnd\r
+  // is called more than once on an irp (which itself is a bug, it should only be called one time).\r
+  KeAcquireSpinLock(&SpinLock, &Irql);\r
+  if (Record->Previous == NULL) {\r
+    IrpList = Record->Next;\r
+  } else {\r
+    Record->Previous->Next = Record->Next;\r
+  }\r
+  if (Record->Next != NULL) {\r
+    Record->Next->Previous = Record->Previous;\r
+  }\r
+  KeReleaseSpinLock(&SpinLock, Irql);\r
+\r
+  DbgPrint("IRP %d: %s -> 0x%08x\n", Record->Number, Record->DebugMessage, Status);\r
+  ExFreePool(Record->DebugMessage);\r
+  ExFreePool(Record);\r
+}\r
+\r
+VOID STDCALL DecodeIrp(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PCHAR DebugMessage) {\r
+  PDEVICEEXTENSION DeviceExtension = (PDEVICEEXTENSION)DeviceObject->DeviceExtension;\r
+  PIO_STACK_LOCATION Stack = IoGetCurrentIrpStackLocation(Irp);\r
+  PSCSI_REQUEST_BLOCK Srb;\r
+  PCDB Cdb;\r
+  ULONG StartSector, SectorCount;\r
+  PSTORAGE_PROPERTY_QUERY StoragePropertyQuery;\r
+\r
+  sprintf(DebugMessage, "%s %s", (DeviceExtension->IsBus?"Bus":"Disk"), MajorFunctionString(Stack->MajorFunction));\r
+  switch (Stack->MajorFunction) {\r
+    case IRP_MJ_SYSTEM_CONTROL:\r
+      sprintf(DebugMessage, "%s %s", DebugMessage, SystemControlMinorFunctionString(Stack->MinorFunction));\r
+      break;\r
+    case IRP_MJ_PNP:\r
+      sprintf(DebugMessage, "%s %s", DebugMessage, PnPMinorFunctionString(Stack->MinorFunction));\r
+      switch (Stack->MinorFunction) {\r
+        case IRP_MN_QUERY_ID:\r
+          sprintf(DebugMessage, "%s %s", DebugMessage, QueryIdString(Stack->Parameters.QueryId.IdType));\r
+          break;\r
+        case IRP_MN_QUERY_DEVICE_TEXT:\r
+          sprintf(DebugMessage, "%s %s", DebugMessage, DeviceTextTypeString(Stack->Parameters.QueryDeviceText.DeviceTextType));\r
+          break;\r
+        case IRP_MN_QUERY_DEVICE_RELATIONS:\r
+          sprintf(DebugMessage, "%s %s", DebugMessage, QueryDeviceRelationsString(Stack->Parameters.QueryDeviceRelations.Type));\r
+          break;\r
+      }\r
+      break;\r
+    case IRP_MJ_DEVICE_CONTROL:\r
+      sprintf(DebugMessage, "%s (0x%08x) %s", DebugMessage, (int)Stack->Parameters.DeviceIoControl.IoControlCode, DeviceIoControlString(Stack->Parameters.DeviceIoControl.IoControlCode));\r
+      if (!DeviceExtension->IsBus && Stack->Parameters.DeviceIoControl.IoControlCode == IOCTL_STORAGE_QUERY_PROPERTY) {\r
+        StoragePropertyQuery = Irp->AssociatedIrp.SystemBuffer;\r
+        switch (StoragePropertyQuery->PropertyId) {\r
+          case StorageDeviceProperty:  sprintf(DebugMessage, "%s StorageDeviceProperty", DebugMessage); break;\r
+          case StorageAdapterProperty: sprintf(DebugMessage, "%s StorageAdapterProperty", DebugMessage); break;\r
+          default:                     sprintf(DebugMessage, "%s StorageUnknownProperty (%d)", DebugMessage, StoragePropertyQuery->PropertyId);\r
+        }\r
+        switch (StoragePropertyQuery->QueryType) {\r
+          case PropertyStandardQuery: sprintf(DebugMessage, "%s PropertyStandardQuery", DebugMessage); break;\r
+          case PropertyExistsQuery:   sprintf(DebugMessage, "%s PropertyExistsQuery", DebugMessage); break;\r
+          default:                    sprintf(DebugMessage, "%s PropertyUnknownQuery (%d)", DebugMessage, StoragePropertyQuery->QueryType);\r
+        }\r
+      }\r
+      break;\r
+    case IRP_MJ_SCSI:\r
+      if (!DeviceExtension->IsBus) {\r
+        Srb = Stack->Parameters.Scsi.Srb;\r
+        Cdb = (PCDB)Srb->Cdb;\r
+        sprintf(DebugMessage, "%s %s", DebugMessage, SrbFunctionString(Srb->Function));\r
+        if (Srb->Lun == 0 && Srb->Function == SRB_FUNCTION_EXECUTE_SCSI) {\r
+          sprintf(DebugMessage, "%s %s", DebugMessage, SCSIOPString(Cdb->AsByte[0]));\r
+          if (Cdb->AsByte[0] == SCSIOP_READ || Cdb->AsByte[0] == SCSIOP_WRITE || Cdb->AsByte[0] == SCSIOP_VERIFY) {\r
+            StartSector = (Cdb->CDB10.LogicalBlockByte0 << 24) + (Cdb->CDB10.LogicalBlockByte1 << 16) + (Cdb->CDB10.LogicalBlockByte2 << 8) + Cdb->CDB10.LogicalBlockByte3;\r
+            SectorCount = (Cdb->CDB10.TransferBlocksMsb << 8 ) + Cdb->CDB10.TransferBlocksLsb;\r
+            sprintf(DebugMessage, "%s %d %d", DebugMessage, (int)StartSector, (int)SectorCount);\r
+          }\r
+          if (Cdb->AsByte[0] == SCSIOP_READ || Cdb->AsByte[0] == SCSIOP_WRITE) {\r
+            sprintf(DebugMessage, "%s (buffersize: %d)", DebugMessage, (int)Srb->DataTransferLength);\r
+          }\r
+        }\r
+      }\r
+      break;\r
+  }\r
+}\r
+\r
+PCHAR STDCALL MajorFunctionString(IN UCHAR MajorFunction) {\r
+  switch (MajorFunction) {\r
+    case IRP_MJ_CREATE:                   return "CREATE";\r
+//    case IRP_MJ_NAMED_PIPE:               return "NAMED_PIPE";\r
+    case IRP_MJ_CLOSE:                    return "CLOSE";\r
+    case IRP_MJ_READ:                     return "READ";\r
+    case IRP_MJ_WRITE:                    return "WRITE";\r
+    case IRP_MJ_QUERY_INFORMATION:        return "QUERY_INFORMATION";\r
+    case IRP_MJ_SET_INFORMATION:          return "SET_INFORMATION";\r
+    case IRP_MJ_QUERY_EA:                 return "QUERY_EA";\r
+    case IRP_MJ_SET_EA:                   return "SET_EA";\r
+    case IRP_MJ_FLUSH_BUFFERS:            return "FLUSH_BUFFERS";\r
+    case IRP_MJ_QUERY_VOLUME_INFORMATION: return "QUERY_VOLUME_INFORMATION";\r
+    case IRP_MJ_SET_VOLUME_INFORMATION:   return "SET_VOLUME_INFORMATION";\r
+    case IRP_MJ_DIRECTORY_CONTROL:        return "DIRECTORY_CONTROL";\r
+    case IRP_MJ_FILE_SYSTEM_CONTROL:      return "FILE_SYSTEM_CONTROL";\r
+    case IRP_MJ_DEVICE_CONTROL:           return "DEVICE_CONTROL";\r
+//    case IRP_MJ_INTERNAL_DEVICE_CONTROL:  return "INTERNAL_DEVICE_CONTROL";\r
+    case IRP_MJ_SCSI:                     return "SCSI";\r
+    case IRP_MJ_SHUTDOWN:                 return "SHUTDOWN";\r
+    case IRP_MJ_LOCK_CONTROL:             return "LOCK_CONTROL";\r
+    case IRP_MJ_CLEANUP:                  return "CLEANUP";\r
+    case IRP_MJ_CREATE_MAILSLOT:          return "CREATE_MAILSLOT";\r
+    case IRP_MJ_QUERY_SECURITY:           return "QUERY_SECURITY";\r
+    case IRP_MJ_SET_SECURITY:             return "SET_SECURITY";\r
+    case IRP_MJ_POWER:                    return "POWER";\r
+    case IRP_MJ_SYSTEM_CONTROL:           return "SYSTEM_CONTROL";\r
+    case IRP_MJ_DEVICE_CHANGE:            return "DEVICE_CHANGE";\r
+    case IRP_MJ_QUERY_QUOTA:              return "QUERY_QUOTA";\r
+    case IRP_MJ_SET_QUOTA:                return "SET_QUOTA";\r
+    case IRP_MJ_PNP:                      return "PNP";\r
+//    case IRP_MJ_PNP_POWER:                return "PNP_POWER";\r
+//    case IRP_MJ_MAXIMUM_FUNCTION:         return "MAXIMUM_FUNCTION";\r
+    default:                              return "UNKNOWN";\r
+  }\r
+}\r
+\r
+PCHAR STDCALL PnPMinorFunctionString(IN UCHAR MinorFunction) {\r
+  switch (MinorFunction) {\r
+    case IRP_MN_START_DEVICE:                 return "START_DEVICE";\r
+    case IRP_MN_QUERY_REMOVE_DEVICE:          return "QUERY_REMOVE_DEVICE";\r
+    case IRP_MN_REMOVE_DEVICE:                return "REMOVE_DEVICE";\r
+    case IRP_MN_CANCEL_REMOVE_DEVICE:         return "CANCEL_REMOVE_DEVICE";\r
+    case IRP_MN_STOP_DEVICE:                  return "STOP_DEVICE";\r
+    case IRP_MN_QUERY_STOP_DEVICE:            return "QUERY_STOP_DEVICE";\r
+    case IRP_MN_CANCEL_STOP_DEVICE:           return "CANCEL_STOP_DEVICE";\r
+    case IRP_MN_QUERY_DEVICE_RELATIONS:       return "QUERY_DEVICE_RELATIONS";\r
+    case IRP_MN_QUERY_INTERFACE:              return "QUERY_INTERFACE";\r
+    case IRP_MN_QUERY_CAPABILITIES:           return "QUERY_CAPABILITIES";\r
+    case IRP_MN_QUERY_RESOURCES:              return "QUERY_RESOURCES";\r
+    case IRP_MN_QUERY_RESOURCE_REQUIREMENTS:  return "QUERY_RESOURCE_REQUIREMENTS";\r
+    case IRP_MN_QUERY_DEVICE_TEXT:            return "QUERY_DEVICE_TEXT";\r
+    case IRP_MN_FILTER_RESOURCE_REQUIREMENTS: return "FILTER_RESOURCE_REQUIREMENTS";\r
+    case IRP_MN_READ_CONFIG:                  return "READ_CONFIG";\r
+    case IRP_MN_WRITE_CONFIG:                 return "WRITE_CONFIG";\r
+    case IRP_MN_EJECT:                        return "EJECT";\r
+    case IRP_MN_SET_LOCK:                     return "SET_LOCK";\r
+    case IRP_MN_QUERY_ID:                     return "QUERY_ID";\r
+    case IRP_MN_QUERY_PNP_DEVICE_STATE:       return "QUERY_PNP_DEVICE_STATE";\r
+    case IRP_MN_QUERY_BUS_INFORMATION:        return "QUERY_BUS_INFORMATION";\r
+    case IRP_MN_DEVICE_USAGE_NOTIFICATION:    return "DEVICE_USAGE_NOTIFICATION";\r
+    case IRP_MN_SURPRISE_REMOVAL:             return "SURPRISE_REMOVAL";\r
+    case IRP_MN_QUERY_LEGACY_BUS_INFORMATION: return "QUERY_LEGACY_BUS_INFORMATION";\r
+//    case IRP_MN_BUS_RESET:                    return "BUS_RESET"\r
+    default:                                  return "UNKNOWN";\r
+  }\r
+}\r
+\r
+PCHAR STDCALL SystemControlMinorFunctionString(IN UCHAR MinorFunction) {\r
+  switch (MinorFunction) {\r
+    case IRP_MN_QUERY_ALL_DATA:         return "QUERY_ALL_DATA";\r
+    case IRP_MN_QUERY_SINGLE_INSTANCE:  return "QUERY_SINGLE_INSTANCE";\r
+    case IRP_MN_CHANGE_SINGLE_INSTANCE: return "CHANGE_SINGLE_INSTANCE";\r
+    case IRP_MN_CHANGE_SINGLE_ITEM:     return "CHANGE_SINGLE_ITEM";\r
+    case IRP_MN_ENABLE_EVENTS:          return "ENABLE_EVENTS";\r
+    case IRP_MN_DISABLE_EVENTS:         return "DISABLE_EVENTS";\r
+    case IRP_MN_ENABLE_COLLECTION:      return "ENABLE_COLLECTION";\r
+    case IRP_MN_DISABLE_COLLECTION:     return "DISABLE_COLLECTION";\r
+    case IRP_MN_REGINFO:                return "REGINFO";\r
+    case IRP_MN_EXECUTE_METHOD:         return "EXECUTE_METHOD";\r
+//    case IRP_MN_REGINFO_EX:             return "REGINFO_EX";\r
+    default:                            return "UNKNOWN";\r
+  }\r
+}\r
+\r
+PCHAR STDCALL PowerMinorFunctionString(IN UCHAR MinorFunction) {\r
+  switch (MinorFunction) {\r
+    case IRP_MN_WAIT_WAKE:      return "WAIT_WAKE";\r
+    case IRP_MN_POWER_SEQUENCE: return "POWER_SEQUENCE";\r
+    case IRP_MN_SET_POWER:      return "SET_POWER";\r
+    case IRP_MN_QUERY_POWER:    return "QUERY_POWER";\r
+    default:                    return "UNKNOWN";\r
+  }\r
+}\r
+\r
+PCHAR STDCALL QueryDeviceRelationsString(IN DEVICE_RELATION_TYPE Type) {\r
+  switch (Type) {\r
+    case BusRelations:         return "BusRelations";\r
+    case EjectionRelations:    return "EjectionRelations";\r
+    case RemovalRelations:     return "RemovalRelations";\r
+    case TargetDeviceRelation: return "TargetDeviceRelation";\r
+    default:                   return "UnknownRelation";\r
+  }\r
+}\r
+\r
+PCHAR STDCALL QueryIdString(IN BUS_QUERY_ID_TYPE IdType) {\r
+  switch (IdType) {\r
+    case BusQueryDeviceID:           return "BusQueryDeviceID";\r
+    case BusQueryHardwareIDs:        return "BusQueryHardwareIDs";\r
+    case BusQueryCompatibleIDs:      return "BusQueryCompatibleIDs";\r
+    case BusQueryInstanceID:         return "BusQueryInstanceID";\r
+    case BusQueryDeviceSerialNumber: return "BusQueryDeviceSerialNumber";\r
+    default:                         return "BusQueryUnknown";\r
+  }\r
+}\r
+\r
+PCHAR STDCALL SrbFunctionString(IN UCHAR Function) {\r
+  switch (Function) {\r
+    case SRB_FUNCTION_EXECUTE_SCSI:       return "EXECUTE_SCSI";\r
+    case SRB_FUNCTION_CLAIM_DEVICE:       return "CLAIM_DEVICE";\r
+    case SRB_FUNCTION_IO_CONTROL:         return "IO_CONTROL";\r
+    case SRB_FUNCTION_RECEIVE_EVENT:      return "RECEIVE_EVENT";\r
+    case SRB_FUNCTION_RELEASE_QUEUE:      return "RELEASE_QUEUE";\r
+    case SRB_FUNCTION_ATTACH_DEVICE:      return "ATTACH_DEVICE";\r
+    case SRB_FUNCTION_RELEASE_DEVICE:     return "RELEASE_DEVICE";\r
+    case SRB_FUNCTION_SHUTDOWN:           return "SHUTDOWN";\r
+    case SRB_FUNCTION_FLUSH:              return "FLUSH";\r
+    case SRB_FUNCTION_ABORT_COMMAND:      return "ABORT_COMMAND";\r
+    case SRB_FUNCTION_RELEASE_RECOVERY:   return "RELEASE_RECOVERY";\r
+    case SRB_FUNCTION_RESET_BUS:          return "RESET_BUS";\r
+    case SRB_FUNCTION_RESET_DEVICE:       return "RESET_DEVICE";\r
+    case SRB_FUNCTION_TERMINATE_IO:       return "TERMINATE_IO";\r
+    case SRB_FUNCTION_FLUSH_QUEUE:        return "FLUSH_QUEUE";\r
+    case SRB_FUNCTION_REMOVE_DEVICE:      return "REMOVE_DEVICE";\r
+    case SRB_FUNCTION_WMI:                return "WMI";\r
+    case SRB_FUNCTION_LOCK_QUEUE:         return "LOCK_QUEUE";\r
+    case SRB_FUNCTION_UNLOCK_QUEUE:       return "UNLOCK_QUEUE";\r
+//    case SRB_FUNCTION_RESET_LOGICAL_UNIT: return "RESET_LOGICAL_UNIT";\r
+    default:                              return "SRB_FUNCTION_UNKNOWN";\r
+  }\r
+}\r
+\r
+PCHAR STDCALL DeviceIoControlString(IN ULONG IoControlCode) {\r
+  switch (IoControlCode) {\r
+    case IOCTL_SCSI_GET_INQUIRY_DATA:           return "IOCTL_SCSI_GET_INQUIRY_DATA";\r
+    case IOCTL_SCSI_GET_CAPABILITIES:           return "IOCTL_SCSI_GET_CAPABILITIES";\r
+    case IOCTL_SCSI_GET_ADDRESS:                return "IOCTL_SCSI_GET_ADDRESS";\r
+    case IOCTL_SCSI_MINIPORT:                   return "IOCTL_SCSI_MINIPORT";\r
+    case IOCTL_SCSI_PASS_THROUGH:               return "IOCTL_SCSI_PASS_THROUGH";\r
+    case IOCTL_SCSI_PASS_THROUGH_DIRECT:        return "IOCTL_SCSI_PASS_THROUGH_DIRECT";\r
+    case IOCTL_SCSI_RESCAN_BUS:                 return "IOCTL_SCSI_RESCAN_BUS";\r
+    case IOCTL_DISK_CHECK_VERIFY:               return "IOCTL_DISK_CHECK_VERIFY";\r
+    case IOCTL_DISK_CONTROLLER_NUMBER:          return "IOCTL_DISK_CONTROLLER_NUMBER";\r
+//    case IOCTL_DISK_CREATE_DISK:                return "IOCTL_DISK_CREATE_DISK";\r
+    case IOCTL_DISK_DELETE_DRIVE_LAYOUT:        return "IOCTL_DISK_DELETE_DRIVE_LAYOUT";\r
+    case IOCTL_DISK_FIND_NEW_DEVICES:           return "IOCTL_DISK_FIND_NEW_DEVICES";\r
+    case IOCTL_DISK_FORMAT_TRACKS:              return "IOCTL_DISK_FORMAT_TRACKS";\r
+    case IOCTL_DISK_FORMAT_TRACKS_EX:           return "IOCTL_DISK_FORMAT_TRACKS_EX";\r
+    case IOCTL_DISK_GET_CACHE_INFORMATION:      return "IOCTL_DISK_GET_CACHE_INFORMATION";\r
+    case IOCTL_DISK_GET_DRIVE_GEOMETRY:         return "IOCTL_DISK_GET_DRIVE_GEOMETRY";\r
+//    case IOCTL_DISK_GET_DRIVE_GEOMETRY_EX:      return "IOCTL_DISK_GET_DRIVE_GEOMETRY_EX";\r
+    case IOCTL_DISK_GET_DRIVE_LAYOUT:           return "IOCTL_DISK_GET_DRIVE_LAYOUT";\r
+//    case IOCTL_DISK_GET_DRIVE_LAYOUT_EX:        return "IOCTL_DISK_GET_DRIVE_LAYOUT_EX";\r
+    case IOCTL_DISK_GET_MEDIA_TYPES:            return "IOCTL_DISK_GET_MEDIA_TYPES";\r
+//    case IOCTL_DISK_GET_LENGTH_INFO:            return "IOCTL_DISK_GET_LENGTH_INFO";\r
+    case IOCTL_DISK_GET_PARTITION_INFO:         return "IOCTL_DISK_GET_PARTITION_INFO";\r
+//    case IOCTL_DISK_GET_PARTITION_INFO_EX:      return "IOCTL_DISK_GET_PARTITION_INFO_EX";\r
+    case IOCTL_DISK_GROW_PARTITION:             return "IOCTL_DISK_GROW_PARTITION";\r
+    case IOCTL_DISK_INTERNAL_CLEAR_VERIFY:      return "IOCTL_DISK_INTERNAL_CLEAR_VERIFY";\r
+    case IOCTL_DISK_INTERNAL_SET_VERIFY:        return "IOCTL_DISK_INTERNAL_SET_VERIFY";\r
+    case IOCTL_DISK_IS_WRITABLE:                return "IOCTL_DISK_IS_WRITABLE";\r
+    case IOCTL_DISK_PERFORMANCE:                return "IOCTL_DISK_PERFORMANCE";\r
+//    case IOCTL_DISK_PERFORMANCE_OFF:            return "IOCTL_DISK_PERFORMANCE_OFF";\r
+    case IOCTL_DISK_REASSIGN_BLOCKS:            return "IOCTL_DISK_REASSIGN_BLOCKS";\r
+    case IOCTL_DISK_RESERVE:                    return "IOCTL_DISK_RESERVE";\r
+    case IOCTL_DISK_SET_CACHE_INFORMATION:      return "IOCTL_DISK_SET_CACHE_INFORMATION";\r
+    case IOCTL_DISK_SET_DRIVE_LAYOUT:           return "IOCTL_DISK_SET_DRIVE_LAYOUT";\r
+//    case IOCTL_DISK_SET_DRIVE_LAYOUT_EX:        return "IOCTL_DISK_SET_DRIVE_LAYOUT_EX";\r
+    case IOCTL_DISK_SET_PARTITION_INFO:         return "IOCTL_DISK_SET_PARTITION_INFO";\r
+//    case IOCTL_DISK_SET_PARTITION_INFO_EX:      return "IOCTL_DISK_SET_PARTITION_INFO_EX";\r
+    case IOCTL_DISK_VERIFY:                     return "IOCTL_DISK_VERIFY";\r
+    case SMART_GET_VERSION:                     return "SMART_GET_VERSION";\r
+    case SMART_RCV_DRIVE_DATA:                  return "SMART_RCV_DRIVE_DATA";\r
+    case SMART_SEND_DRIVE_COMMAND:              return "SMART_SEND_DRIVE_COMMAND";\r
+    case IOCTL_STORAGE_CHECK_VERIFY:            return "IOCTL_STORAGE_CHECK_VERIFY";\r
+    case IOCTL_STORAGE_CHECK_VERIFY2:           return "IOCTL_STORAGE_CHECK_VERIFY2";\r
+    case IOCTL_STORAGE_EJECT_MEDIA:             return "IOCTL_STORAGE_EJECT_MEDIA";\r
+    case IOCTL_STORAGE_EJECTION_CONTROL:        return "IOCTL_STORAGE_EJECTION_CONTROL";\r
+    case IOCTL_STORAGE_FIND_NEW_DEVICES:        return "IOCTL_STORAGE_FIND_NEW_DEVICES";\r
+    case IOCTL_STORAGE_GET_DEVICE_NUMBER:       return "IOCTL_STORAGE_GET_DEVICE_NUMBER";\r
+//    case IOCTL_STORAGE_GET_MEDIA_SERIAL_NUMBER: return "IOCTL_STORAGE_GET_MEDIA_SERIAL_NUMBER";\r
+    case IOCTL_STORAGE_GET_MEDIA_TYPES:         return "IOCTL_STORAGE_GET_MEDIA_TYPES";\r
+    case IOCTL_STORAGE_GET_MEDIA_TYPES_EX:      return "IOCTL_STORAGE_GET_MEDIA_TYPES_EX";\r
+    case IOCTL_STORAGE_LOAD_MEDIA:              return "IOCTL_STORAGE_LOAD_MEDIA";\r
+    case IOCTL_STORAGE_LOAD_MEDIA2:             return "IOCTL_STORAGE_LOAD_MEDIA2";\r
+    case IOCTL_STORAGE_MCN_CONTROL:             return "IOCTL_STORAGE_MCN_CONTROL";\r
+    case IOCTL_STORAGE_MEDIA_REMOVAL:           return "IOCTL_STORAGE_MEDIA_REMOVAL";\r
+    case IOCTL_STORAGE_PREDICT_FAILURE:         return "IOCTL_STORAGE_PREDICT_FAILURE";\r
+    case IOCTL_STORAGE_QUERY_PROPERTY:          return "IOCTL_STORAGE_QUERY_PROPERTY";\r
+    case IOCTL_STORAGE_RELEASE:                 return "IOCTL_STORAGE_RELEASE";\r
+    case IOCTL_STORAGE_RESERVE:                 return "IOCTL_STORAGE_RESERVE";\r
+    case IOCTL_STORAGE_RESET_BUS:               return "IOCTL_STORAGE_RESET_BUS";\r
+    case IOCTL_STORAGE_RESET_DEVICE:            return "IOCTL_STORAGE_RESET_DEVICE";\r
+    case IOCTL_AOE_SCAN:                        return "IOCTL_AOE_SCAN";\r
+    case IOCTL_AOE_SHOW:                        return "IOCTL_AOE_SHOW";\r
+    case IOCTL_AOE_MOUNT:                       return "IOCTL_AOE_MOUNT";\r
+    case IOCTL_AOE_UMOUNT:                      return "IOCTL_AOE_UMOUNT";\r
+    default:                                    return "IOCTL_UNKNOWN";\r
+  }\r
+}\r
+\r
+PCHAR STDCALL DeviceTextTypeString(IN DEVICE_TEXT_TYPE DeviceTextType) {\r
+  switch (DeviceTextType) {\r
+    case DeviceTextDescription:         return "DeviceTextDescription";\r
+    case DeviceTextLocationInformation: return "DeviceTextLocationInformation";\r
+    default:                            return "DeviceTextUnknown";\r
+  }\r
+}\r
+\r
+PCHAR STDCALL SCSIOPString(IN UCHAR OperationCode) {\r
+  switch (OperationCode) {\r
+    case SCSIOP_TEST_UNIT_READY: return "TEST_UNIT_READY";\r
+    case SCSIOP_READ:            return "READ";\r
+    case SCSIOP_WRITE:           return "WRITE";\r
+    case SCSIOP_VERIFY:          return "VERIFY";\r
+    case SCSIOP_READ_CAPACITY:   return "READ_CAPACITY";\r
+    case SCSIOP_MODE_SENSE:      return "MODE_SENSE";\r
+    case SCSIOP_MEDIUM_REMOVAL:  return "MEDIUM_REMOVAL";\r
+    case SCSIOP_READ16:          return "READ16";\r
+    case SCSIOP_WRITE16:         return "WRITE16";\r
+    case SCSIOP_VERIFY16:        return "VERIFY16";\r
+    case SCSIOP_READ_CAPACITY16: return "CAPACITY16";\r
+    default:                     return "SCSIOP_UNKNOWN";\r
+  }\r
+}\r
diff --git a/src/disk.c b/src/disk.c
new file mode 100644 (file)
index 0000000..bd65043
--- /dev/null
@@ -0,0 +1,617 @@
+/*\r
+  Copyright 2006-2008, V.\r
+  For contact information, see http://winaoe.org/\r
+\r
+  This file is part of WinAoE.\r
+\r
+  WinAoE is free software: you can redistribute it and/or modify\r
+  it under the terms of the GNU General Public License as published by\r
+  the Free Software Foundation, either version 3 of the License, or\r
+  (at your option) any later version.\r
+\r
+  WinAoE is distributed in the hope that it will be useful,\r
+  but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+  GNU General Public License for more details.\r
+\r
+  You should have received a copy of the GNU General Public License\r
+  along with WinAoE.  If not, see <http://www.gnu.org/licenses/>.\r
+*/\r
+\r
+#include "portable.h"\r
+#include <stdio.h>\r
+#include <ntddk.h>\r
+#include <srb.h>\r
+#include <scsi.h>\r
+#include <ntddscsi.h>\r
+#include <ntddstor.h>\r
+#include <ntdddisk.h>\r
+#include <initguid.h>\r
+#include "driver.h"\r
+#include "aoe.h"\r
+\r
+#ifndef _MSC_VER\r
+long long __divdi3(long long u, long long v) {return u / v;}\r
+#endif\r
+\r
+#ifdef _MSC_VER\r
+#if _WIN32_WINNT <= 0x0500\r
+#ifdef _MSC_VER\r
+#pragma pack(1)\r
+#endif\r
+typedef union _EIGHT_BYTE {\r
+  struct {\r
+    UCHAR Byte0;\r
+    UCHAR Byte1;\r
+    UCHAR Byte2;\r
+    UCHAR Byte3;\r
+    UCHAR Byte4;\r
+    UCHAR Byte5;\r
+    UCHAR Byte6;\r
+    UCHAR Byte7;\r
+  };\r
+  ULONGLONG AsULongLong;\r
+} __attribute__((__packed__)) EIGHT_BYTE, *PEIGHT_BYTE;\r
+#ifdef _MSC_VER\r
+#pragma pack()\r
+#endif\r
+\r
+#define REVERSE_BYTES_QUAD(Destination, Source) { \\r
+  PEIGHT_BYTE d = (PEIGHT_BYTE)(Destination);     \\r
+  PEIGHT_BYTE s = (PEIGHT_BYTE)(Source);          \\r
+  d->Byte7 = s->Byte0;                            \\r
+  d->Byte6 = s->Byte1;                            \\r
+  d->Byte5 = s->Byte2;                            \\r
+  d->Byte4 = s->Byte3;                            \\r
+  d->Byte3 = s->Byte4;                            \\r
+  d->Byte2 = s->Byte5;                            \\r
+  d->Byte1 = s->Byte6;                            \\r
+  d->Byte0 = s->Byte7;                            \\r
+}\r
+#endif\r
+#endif\r
+\r
+#if _WIN32_WINNT < 0x0502\r
+#ifdef _MSC_VER\r
+#pragma pack(1)\r
+#endif\r
+typedef struct _READ_CAPACITY_DATA_EX {\r
+  LARGE_INTEGER LogicalBlockAddress;\r
+  ULONG BytesPerBlock;\r
+} __attribute__((__packed__)) READ_CAPACITY_DATA_EX, *PREAD_CAPACITY_DATA_EX;\r
+#ifdef _MSC_VER\r
+#pragma pack()\r
+#endif\r
+#endif\r
+\r
+#ifdef _MSC_VER\r
+#pragma pack(1)\r
+#endif\r
+typedef struct _PORTABLE_CDB16 {\r
+  UCHAR OperationCode;\r
+  UCHAR Reserved1:3;\r
+  UCHAR ForceUnitAccess:1;\r
+  UCHAR DisablePageOut:1;\r
+  UCHAR Protection:3;\r
+  UCHAR LogicalBlock[8];\r
+  UCHAR TransferLength[4];\r
+  UCHAR Reserved2;\r
+  UCHAR Control;\r
+} __attribute__((__packed__)) CDB16, *PCDB16;\r
+#ifdef _MSC_VER\r
+#pragma pack()\r
+#endif\r
+\r
+DEFINE_GUID(GUID_BUS_TYPE_INTERNAL, 0x2530ea73L, 0x086b, 0x11d1, 0xa0, 0x9f, 0x00, 0xc0, 0x4f, 0xc3, 0x40, 0xb1);\r
+\r
+// in this file\r
+NTSTATUS STDCALL BusGetDeviceCapabilities(IN PDEVICE_OBJECT DeviceObject, IN PDEVICE_CAPABILITIES DeviceCapabilities);\r
+\r
+NTSTATUS STDCALL DiskDispatchPnP(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PIO_STACK_LOCATION Stack, IN PDEVICEEXTENSION DeviceExtension) {\r
+  NTSTATUS Status;\r
+  PDEVICE_RELATIONS DeviceRelations;\r
+  PPNP_BUS_INFORMATION PnPBusInformation;\r
+  PDEVICE_CAPABILITIES DeviceCapabilities;\r
+  DEVICE_CAPABILITIES ParentDeviceCapabilities;\r
+  PWCHAR String;\r
+  ULONG StringLength;\r
+\r
+  switch (Stack->MinorFunction) {\r
+    case IRP_MN_QUERY_ID:\r
+      if ((String = (PWCHAR)ExAllocatePool(NonPagedPool, (512 * sizeof(WCHAR)))) == NULL) {\r
+        DbgPrint("DiskDispatchPnP ExAllocatePool IRP_MN_QUERY_ID\n");\r
+        Status = STATUS_INSUFFICIENT_RESOURCES;\r
+        break;\r
+      }\r
+      RtlZeroMemory(String, (512 * sizeof(WCHAR)));\r
+      switch (Stack->Parameters.QueryId.IdType) {\r
+        case BusQueryDeviceID:\r
+          StringLength = swprintf(String, L"AoE\\e%d.%d", DeviceExtension->Disk.Major, DeviceExtension->Disk.Minor) + 1;\r
+          if ((Irp->IoStatus.Information = (ULONG_PTR)ExAllocatePool(PagedPool, StringLength * sizeof(WCHAR))) == 0) {\r
+            DbgPrint("DiskDispatchPnP ExAllocatePool BusQueryDeviceID\n");\r
+            Status = STATUS_INSUFFICIENT_RESOURCES;\r
+            break;\r
+          }\r
+          RtlCopyMemory((PWCHAR)Irp->IoStatus.Information, String, StringLength * sizeof(WCHAR));\r
+          Status = STATUS_SUCCESS;\r
+          break;\r
+        case BusQueryInstanceID:\r
+          StringLength = swprintf(String, L"AOEDISK%d.%d", DeviceExtension->Disk.Major, DeviceExtension->Disk.Minor) + 1;\r
+          if ((Irp->IoStatus.Information = (ULONG_PTR)ExAllocatePool(PagedPool, StringLength * sizeof(WCHAR))) == 0) {\r
+            DbgPrint("DiskDispatchPnP ExAllocatePool BusQueryInstanceID\n");\r
+            Status = STATUS_INSUFFICIENT_RESOURCES;\r
+            break;\r
+          }\r
+          RtlCopyMemory((PWCHAR)Irp->IoStatus.Information, String, StringLength * sizeof(WCHAR));\r
+          Status = STATUS_SUCCESS;\r
+          break;\r
+        case BusQueryHardwareIDs:\r
+          StringLength = swprintf(String, L"AoE\\e%d.%d", DeviceExtension->Disk.Major, DeviceExtension->Disk.Minor) + 1;\r
+          StringLength += swprintf(&String[StringLength], L"GenDisk") + 4;\r
+          if ((Irp->IoStatus.Information = (ULONG_PTR)ExAllocatePool(PagedPool, StringLength * sizeof(WCHAR))) == 0) {\r
+            DbgPrint("DiskDispatchPnP ExAllocatePool BusQueryHardwareIDs\n");\r
+            Status = STATUS_INSUFFICIENT_RESOURCES;\r
+            break;\r
+          }\r
+          RtlCopyMemory((PWCHAR)Irp->IoStatus.Information, String, StringLength * sizeof(WCHAR));\r
+          Status = STATUS_SUCCESS;\r
+          break;\r
+        case BusQueryCompatibleIDs:\r
+          StringLength = swprintf(String, L"GenDisk") + 4;\r
+          if ((Irp->IoStatus.Information = (ULONG_PTR)ExAllocatePool(PagedPool, StringLength * sizeof(WCHAR))) == 0) {\r
+            DbgPrint("DiskDispatchPnP ExAllocatePool BusQueryCompatibleIDs\n");\r
+            Status = STATUS_INSUFFICIENT_RESOURCES;\r
+            break;\r
+          }\r
+          RtlCopyMemory((PWCHAR)Irp->IoStatus.Information, String, StringLength * sizeof(WCHAR));\r
+          Status = STATUS_SUCCESS;\r
+          break;\r
+        default:\r
+          Irp->IoStatus.Information = 0;\r
+          Status = STATUS_NOT_SUPPORTED;\r
+      }\r
+      ExFreePool(String);\r
+      break;\r
+    case IRP_MN_QUERY_DEVICE_TEXT:\r
+      if ((String = (PWCHAR)ExAllocatePool(NonPagedPool, (512 * sizeof(WCHAR)))) == NULL) {\r
+        DbgPrint("DiskDispatchPnP ExAllocatePool IRP_MN_QUERY_DEVICE_TEXT\n");\r
+        Status = STATUS_INSUFFICIENT_RESOURCES;\r
+        break;\r
+      }\r
+      RtlZeroMemory(String, (512 * sizeof(WCHAR)));\r
+      switch (Stack->Parameters.QueryDeviceText.DeviceTextType ) {\r
+        case DeviceTextDescription:\r
+          StringLength = swprintf(String, L"AoE Disk") + 1;\r
+          if ((Irp->IoStatus.Information = (ULONG_PTR)ExAllocatePool(PagedPool, StringLength * sizeof(WCHAR))) == 0) {\r
+            DbgPrint("DiskDispatchPnP ExAllocatePool DeviceTextDescription\n");\r
+            Status = STATUS_INSUFFICIENT_RESOURCES;\r
+            break;\r
+          }\r
+          RtlCopyMemory((PWCHAR)Irp->IoStatus.Information, String, StringLength * sizeof(WCHAR));\r
+          Status = STATUS_SUCCESS;\r
+          break;\r
+        case DeviceTextLocationInformation:\r
+          StringLength = swprintf(String, L"AoE e%d.%d", DeviceExtension->Disk.Major, DeviceExtension->Disk.Minor) + 1;\r
+          if ((Irp->IoStatus.Information = (ULONG_PTR)ExAllocatePool(PagedPool, StringLength * sizeof(WCHAR))) == 0) {\r
+            DbgPrint("DiskDispatchPnP ExAllocatePool DeviceTextLocationInformation\n");\r
+            Status = STATUS_INSUFFICIENT_RESOURCES;\r
+            break;\r
+          }\r
+          RtlCopyMemory((PWCHAR)Irp->IoStatus.Information, String, StringLength * sizeof(WCHAR));\r
+          Status = STATUS_SUCCESS;\r
+          break;\r
+        default:\r
+          Irp->IoStatus.Information = 0;\r
+          Status = STATUS_NOT_SUPPORTED;\r
+      }\r
+      ExFreePool(String);\r
+      break;\r
+    case IRP_MN_QUERY_DEVICE_RELATIONS:\r
+      if (Stack->Parameters.QueryDeviceRelations.Type != TargetDeviceRelation) {\r
+        Status = Irp->IoStatus.Status;\r
+        break;\r
+      }\r
+      if ((DeviceRelations = (PDEVICE_RELATIONS)ExAllocatePool(PagedPool, sizeof(DEVICE_RELATIONS) + sizeof (PDEVICE_OBJECT))) == NULL) {\r
+        DbgPrint("DiskDispatchPnP ExAllocatePool IRP_MN_QUERY_DEVICE_RELATIONS\n");\r
+        Status = STATUS_INSUFFICIENT_RESOURCES;\r
+        break;\r
+      }\r
+      DeviceRelations->Objects[0] = DeviceExtension->Self;\r
+      DeviceRelations->Count = 1;\r
+      ObReferenceObject(DeviceExtension->Self);\r
+      Irp->IoStatus.Information = (ULONG_PTR)DeviceRelations;\r
+      Status = STATUS_SUCCESS;\r
+      break;\r
+    case IRP_MN_QUERY_BUS_INFORMATION:\r
+      if ((PnPBusInformation = (PPNP_BUS_INFORMATION)ExAllocatePool(PagedPool, sizeof(PNP_BUS_INFORMATION))) == NULL) {\r
+        DbgPrint("DiskDispatchPnP ExAllocatePool IRP_MN_QUERY_BUS_INFORMATION\n");\r
+        Status = STATUS_INSUFFICIENT_RESOURCES;\r
+        break;\r
+      }\r
+      PnPBusInformation->BusTypeGuid = GUID_BUS_TYPE_INTERNAL;\r
+      PnPBusInformation->LegacyBusType = PNPBus;\r
+      PnPBusInformation->BusNumber = 0;\r
+      Irp->IoStatus.Information = (ULONG_PTR)PnPBusInformation;\r
+      Status = STATUS_SUCCESS;\r
+      break;\r
+    case IRP_MN_QUERY_CAPABILITIES:\r
+      DeviceCapabilities = Stack->Parameters.DeviceCapabilities.Capabilities;\r
+      if (DeviceCapabilities->Version != 1 || DeviceCapabilities->Size < sizeof(DEVICE_CAPABILITIES)) {\r
+        Status = STATUS_UNSUCCESSFUL;\r
+        break;\r
+      }\r
+      if (!NT_SUCCESS(Status = BusGetDeviceCapabilities(((PDEVICEEXTENSION)DeviceExtension->Disk.Parent->DeviceExtension)->Bus.LowerDeviceObject, &ParentDeviceCapabilities))) break;\r
+      RtlCopyMemory(DeviceCapabilities->DeviceState, ParentDeviceCapabilities.DeviceState, (PowerSystemShutdown + 1) * sizeof(DEVICE_POWER_STATE));\r
+      DeviceCapabilities->DeviceState[PowerSystemWorking] = PowerDeviceD0;\r
+      if (DeviceCapabilities->DeviceState[PowerSystemSleeping1] != PowerDeviceD0) DeviceCapabilities->DeviceState[PowerSystemSleeping1] = PowerDeviceD1;\r
+      if (DeviceCapabilities->DeviceState[PowerSystemSleeping2] != PowerDeviceD0) DeviceCapabilities->DeviceState[PowerSystemSleeping2] = PowerDeviceD3;\r
+//      if (DeviceCapabilities->DeviceState[PowerSystemSleeping3] != PowerDeviceD0) DeviceCapabilities->DeviceState[PowerSystemSleeping3] = PowerDeviceD3;\r
+      DeviceCapabilities->DeviceWake = PowerDeviceD1;\r
+      DeviceCapabilities->DeviceD1 = TRUE;\r
+      DeviceCapabilities->DeviceD2 = FALSE;\r
+      DeviceCapabilities->WakeFromD0 = FALSE;\r
+      DeviceCapabilities->WakeFromD1 = FALSE;\r
+      DeviceCapabilities->WakeFromD2 = FALSE;\r
+      DeviceCapabilities->WakeFromD3 = FALSE;\r
+      DeviceCapabilities->D1Latency = 0;\r
+      DeviceCapabilities->D2Latency = 0;\r
+      DeviceCapabilities->D3Latency = 0;\r
+      DeviceCapabilities->EjectSupported = FALSE;\r
+      DeviceCapabilities->HardwareDisabled = FALSE;\r
+      DeviceCapabilities->Removable = FALSE;\r
+      DeviceCapabilities->SurpriseRemovalOK = FALSE;\r
+      DeviceCapabilities->UniqueID = FALSE;\r
+      DeviceCapabilities->SilentInstall = FALSE;\r
+//      DeviceCapabilities->Address = DeviceObject->SerialNo;\r
+//      DeviceCapabilities->UINumber = DeviceObject->SerialNo;\r
+      Status = STATUS_SUCCESS;\r
+      break;\r
+    case IRP_MN_DEVICE_USAGE_NOTIFICATION:\r
+      if (Stack->Parameters.UsageNotification.InPath) {\r
+        DeviceExtension->Disk.SpecialFileCount++;\r
+      } else {\r
+        DeviceExtension->Disk.SpecialFileCount--;\r
+      }\r
+      Irp->IoStatus.Information = 0;\r
+      Status = STATUS_SUCCESS;\r
+      break;\r
+    case IRP_MN_QUERY_PNP_DEVICE_STATE:\r
+      Irp->IoStatus.Information = 0;\r
+      Status = STATUS_SUCCESS;\r
+      break;\r
+    case IRP_MN_START_DEVICE:\r
+      DeviceExtension->OldState = DeviceExtension->State;\r
+      DeviceExtension->State = Started;\r
+      Status = STATUS_SUCCESS;\r
+      break;\r
+    case IRP_MN_QUERY_STOP_DEVICE:\r
+      DeviceExtension->OldState = DeviceExtension->State;\r
+      DeviceExtension->State = StopPending;\r
+      Status = STATUS_SUCCESS;\r
+      break;\r
+    case IRP_MN_CANCEL_STOP_DEVICE:\r
+      DeviceExtension->State = DeviceExtension->OldState;\r
+      Status = STATUS_SUCCESS;\r
+      break;\r
+    case IRP_MN_STOP_DEVICE:\r
+      DeviceExtension->OldState = DeviceExtension->State;\r
+      DeviceExtension->State = Stopped;\r
+      Status = STATUS_SUCCESS;\r
+      break;\r
+    case IRP_MN_QUERY_REMOVE_DEVICE:\r
+      DeviceExtension->OldState = DeviceExtension->State;\r
+      DeviceExtension->State = RemovePending;\r
+      Status = STATUS_SUCCESS;\r
+      break;\r
+    case IRP_MN_REMOVE_DEVICE:\r
+      DeviceExtension->OldState = DeviceExtension->State;\r
+      DeviceExtension->State = NotStarted;\r
+      if (DeviceExtension->Disk.Unmount) {\r
+        IoDeleteDevice(DeviceExtension->Self);\r
+        Status = STATUS_NO_SUCH_DEVICE;\r
+      } else {\r
+        Status = STATUS_SUCCESS;\r
+      }\r
+      break;\r
+    case IRP_MN_CANCEL_REMOVE_DEVICE:\r
+      DeviceExtension->State = DeviceExtension->OldState;\r
+      Status = STATUS_SUCCESS;\r
+      break;\r
+    case IRP_MN_SURPRISE_REMOVAL:\r
+      DeviceExtension->OldState = DeviceExtension->State;\r
+      DeviceExtension->State = SurpriseRemovePending;\r
+      Status = STATUS_SUCCESS;\r
+      break;\r
+    default:\r
+      Status = Irp->IoStatus.Status;\r
+  }\r
+\r
+  Irp->IoStatus.Status = Status;\r
+  IoCompleteRequest(Irp, IO_NO_INCREMENT);\r
+  return Status;\r
+}\r
+\r
+NTSTATUS STDCALL DiskDispatchSCSI(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PIO_STACK_LOCATION Stack, IN PDEVICEEXTENSION DeviceExtension) {\r
+  NTSTATUS Status;\r
+  PSCSI_REQUEST_BLOCK Srb;\r
+  PCDB Cdb;\r
+  LONGLONG StartSector;\r
+  ULONG SectorCount, Temp;\r
+  LONGLONG LargeTemp;\r
+  PMODE_PARAMETER_HEADER ModeParameterHeader;\r
+\r
+  Srb = Stack->Parameters.Scsi.Srb;\r
+  Cdb = (PCDB)Srb->Cdb;\r
+\r
+  Srb->SrbStatus = SRB_STATUS_INVALID_REQUEST;\r
+  Srb->ScsiStatus = SCSISTAT_GOOD;\r
+  Irp->IoStatus.Information = 0;\r
+  Status = STATUS_SUCCESS;\r
+  if (Srb->Lun == 0) {\r
+    switch (Srb->Function) {\r
+      case SRB_FUNCTION_EXECUTE_SCSI:\r
+        switch (Cdb->AsByte[0]) {\r
+          case SCSIOP_TEST_UNIT_READY:\r
+            Srb->SrbStatus = SRB_STATUS_SUCCESS;\r
+            break;\r
+          case SCSIOP_READ:\r
+          case SCSIOP_READ16:\r
+          case SCSIOP_WRITE:\r
+          case SCSIOP_WRITE16:\r
+            if (Cdb->AsByte[0] == SCSIOP_READ16 || Cdb->AsByte[0] == SCSIOP_WRITE16) {\r
+              REVERSE_BYTES_QUAD(&StartSector, &(((PCDB16)Cdb)->LogicalBlock[0]));\r
+              REVERSE_BYTES(&SectorCount, &(((PCDB16)Cdb)->TransferLength[0]));\r
+            } else {\r
+              StartSector = (Cdb->CDB10.LogicalBlockByte0 << 24) + (Cdb->CDB10.LogicalBlockByte1 << 16) + (Cdb->CDB10.LogicalBlockByte2 << 8) + Cdb->CDB10.LogicalBlockByte3;\r
+              SectorCount = (Cdb->CDB10.TransferBlocksMsb << 8) + Cdb->CDB10.TransferBlocksLsb;\r
+            }\r
+            if (StartSector >= DeviceExtension->Disk.LBADiskSize) {\r
+              DbgPrint("!! Fixed SectorCount (StartSector off disk) !!\n");\r
+              SectorCount = 0;\r
+            }\r
+            if ((StartSector + SectorCount > DeviceExtension->Disk.LBADiskSize) && SectorCount != 0) {\r
+              DbgPrint("!! Fixed SectorCount (StartSector + SectorCount off disk) !!\n");\r
+              SectorCount = (ULONG)(DeviceExtension->Disk.LBADiskSize - StartSector);\r
+            }\r
+            if (SectorCount * SECTORSIZE > Srb->DataTransferLength) {\r
+              DbgPrint("!! Fixed SectorCount (DataTransferLength too small) !!\n");\r
+              SectorCount = Srb->DataTransferLength / SECTORSIZE;\r
+            }\r
+            if (Srb->DataTransferLength % SECTORSIZE != 0) DbgPrint("!! DataTransferLength not aligned !!\n");\r
+            if (Srb->DataTransferLength > SectorCount * SECTORSIZE) DbgPrint("!! DataTransferLength too big !!\n");\r
+\r
+            Srb->DataTransferLength = SectorCount * SECTORSIZE;\r
+            Srb->SrbStatus = SRB_STATUS_SUCCESS;\r
+            if (SectorCount == 0) {\r
+              Irp->IoStatus.Information = 0;\r
+              break;\r
+            }\r
+\r
+            if ((((PUCHAR)Srb->DataBuffer - (PUCHAR)MmGetMdlVirtualAddress(Irp->MdlAddress)) + (PUCHAR)MmGetSystemAddressForMdlSafe(Irp->MdlAddress, HighPagePriority)) == NULL) {\r
+              Status = STATUS_INSUFFICIENT_RESOURCES;\r
+              Irp->IoStatus.Information = 0;\r
+              break;\r
+            }\r
+\r
+            if (Cdb->AsByte[0] == SCSIOP_READ || Cdb->AsByte[0] == SCSIOP_READ16) {\r
+              return AoERequest(DeviceExtension, Read, StartSector, SectorCount, ((PUCHAR)Srb->DataBuffer - (PUCHAR)MmGetMdlVirtualAddress(Irp->MdlAddress)) + (PUCHAR)MmGetSystemAddressForMdlSafe(Irp->MdlAddress, HighPagePriority), Irp);\r
+            } else {\r
+              return AoERequest(DeviceExtension, Write, StartSector, SectorCount, ((PUCHAR)Srb->DataBuffer - (PUCHAR)MmGetMdlVirtualAddress(Irp->MdlAddress)) + (PUCHAR)MmGetSystemAddressForMdlSafe(Irp->MdlAddress, HighPagePriority), Irp);\r
+            }\r
+            break;\r
+          case SCSIOP_VERIFY:\r
+          case SCSIOP_VERIFY16:\r
+            if (Cdb->AsByte[0] == SCSIOP_VERIFY16) {\r
+              REVERSE_BYTES_QUAD(&StartSector, &(((PCDB16)Cdb)->LogicalBlock[0]));\r
+              REVERSE_BYTES(&SectorCount, &(((PCDB16)Cdb)->TransferLength[0]));\r
+            } else {\r
+              StartSector = (Cdb->CDB10.LogicalBlockByte0 << 24) + (Cdb->CDB10.LogicalBlockByte1 << 16) + (Cdb->CDB10.LogicalBlockByte2 << 8) + Cdb->CDB10.LogicalBlockByte3;\r
+              SectorCount = (Cdb->CDB10.TransferBlocksMsb << 8) + Cdb->CDB10.TransferBlocksLsb;\r
+            }\r
+//            Srb->DataTransferLength = SectorCount * SECTORSIZE;\r
+            Srb->SrbStatus = SRB_STATUS_SUCCESS;\r
+            break;\r
+          case SCSIOP_READ_CAPACITY:\r
+            Temp = SECTORSIZE;\r
+            REVERSE_BYTES(&(((PREAD_CAPACITY_DATA)Srb->DataBuffer)->BytesPerBlock), &Temp);\r
+            if ((DeviceExtension->Disk.LBADiskSize - 1) > 0xffffffff) {\r
+              ((PREAD_CAPACITY_DATA)Srb->DataBuffer)->LogicalBlockAddress = -1;\r
+            } else {\r
+              Temp = (ULONG)(DeviceExtension->Disk.LBADiskSize - 1);\r
+              REVERSE_BYTES(&(((PREAD_CAPACITY_DATA)Srb->DataBuffer)->LogicalBlockAddress), &Temp);\r
+            }\r
+            Irp->IoStatus.Information = sizeof(READ_CAPACITY_DATA);\r
+            Srb->SrbStatus = SRB_STATUS_SUCCESS;\r
+            Status = STATUS_SUCCESS;\r
+            break;\r
+          case SCSIOP_READ_CAPACITY16:\r
+            Temp = SECTORSIZE;\r
+            REVERSE_BYTES(&(((PREAD_CAPACITY_DATA_EX)Srb->DataBuffer)->BytesPerBlock), &Temp);\r
+            LargeTemp = DeviceExtension->Disk.LBADiskSize - 1;\r
+            REVERSE_BYTES_QUAD(&(((PREAD_CAPACITY_DATA_EX)Srb->DataBuffer)->LogicalBlockAddress.QuadPart), &LargeTemp);\r
+            Irp->IoStatus.Information = sizeof(READ_CAPACITY_DATA_EX);\r
+            Srb->SrbStatus = SRB_STATUS_SUCCESS;\r
+            Status = STATUS_SUCCESS;\r
+            break;\r
+          case SCSIOP_MODE_SENSE:\r
+            if (Srb->DataTransferLength < sizeof(MODE_PARAMETER_HEADER)) {\r
+              Srb->SrbStatus = SRB_STATUS_DATA_OVERRUN;\r
+              break;\r
+            }\r
+            ModeParameterHeader = (PMODE_PARAMETER_HEADER)Srb->DataBuffer;\r
+            RtlZeroMemory(ModeParameterHeader, Srb->DataTransferLength);\r
+            ModeParameterHeader->ModeDataLength = sizeof(MODE_PARAMETER_HEADER);\r
+            ModeParameterHeader->MediumType = FixedMedia;\r
+            ModeParameterHeader->BlockDescriptorLength = 0;\r
+            Srb->DataTransferLength = sizeof(MODE_PARAMETER_HEADER);\r
+            Irp->IoStatus.Information = sizeof(MODE_PARAMETER_HEADER);\r
+            Srb->SrbStatus = SRB_STATUS_SUCCESS;\r
+            break;\r
+          case SCSIOP_MEDIUM_REMOVAL:\r
+            Irp->IoStatus.Information = 0;\r
+            Srb->SrbStatus = SRB_STATUS_SUCCESS;\r
+            Status = STATUS_SUCCESS;\r
+            break;\r
+          default:\r
+            DbgPrint("!!Invalid SCSIOP (%02x)!!\n", Cdb->AsByte[0]);\r
+            Srb->SrbStatus = SRB_STATUS_ERROR;\r
+            Status = STATUS_NOT_IMPLEMENTED;\r
+        }\r
+        break;\r
+      case SRB_FUNCTION_IO_CONTROL:\r
+        Srb->SrbStatus = SRB_STATUS_INVALID_REQUEST;\r
+        break;\r
+      case SRB_FUNCTION_CLAIM_DEVICE:\r
+        Srb->DataBuffer = DeviceObject;\r
+        break;\r
+      case SRB_FUNCTION_RELEASE_DEVICE:\r
+        ObDereferenceObject(DeviceObject);\r
+        break;\r
+      case SRB_FUNCTION_SHUTDOWN:\r
+      case SRB_FUNCTION_FLUSH:\r
+        Srb->SrbStatus = SRB_STATUS_SUCCESS;\r
+        break;\r
+      default:\r
+        DbgPrint("!!Invalid SRB FUNCTION (%08x)!!\n", Srb->Function);\r
+        Status = STATUS_NOT_IMPLEMENTED;\r
+    }\r
+  } else {\r
+    DbgPrint("!!Invalid Lun!!\n");\r
+  }\r
+\r
+  Irp->IoStatus.Status = Status;\r
+  IoCompleteRequest(Irp, IO_NO_INCREMENT);\r
+  return Status;\r
+}\r
+\r
+NTSTATUS STDCALL DiskDispatchDeviceControl(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PIO_STACK_LOCATION Stack, IN PDEVICEEXTENSION DeviceExtension) {\r
+  NTSTATUS Status;\r
+  ULONG CopySize;\r
+  PSTORAGE_PROPERTY_QUERY StoragePropertyQuery;\r
+  STORAGE_ADAPTER_DESCRIPTOR StorageAdapterDescriptor;\r
+  STORAGE_DEVICE_DESCRIPTOR StorageDeviceDescriptor;\r
+  DISK_GEOMETRY DiskGeometry;\r
+  SCSI_ADDRESS ScsiAdress;\r
+\r
+  switch (Stack->Parameters.DeviceIoControl.IoControlCode) {\r
+    case IOCTL_STORAGE_QUERY_PROPERTY:\r
+      StoragePropertyQuery = Irp->AssociatedIrp.SystemBuffer;\r
+      Status = STATUS_INVALID_PARAMETER;\r
+\r
+      if (StoragePropertyQuery->PropertyId == StorageAdapterProperty && StoragePropertyQuery->QueryType == PropertyStandardQuery) {\r
+        CopySize = (Stack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(STORAGE_ADAPTER_DESCRIPTOR)?Stack->Parameters.DeviceIoControl.OutputBufferLength:sizeof(STORAGE_ADAPTER_DESCRIPTOR));\r
+        StorageAdapterDescriptor.Version = sizeof(STORAGE_ADAPTER_DESCRIPTOR);\r
+        StorageAdapterDescriptor.Size = sizeof(STORAGE_ADAPTER_DESCRIPTOR);\r
+        StorageAdapterDescriptor.MaximumTransferLength = SECTORSIZE * DeviceExtension->Disk.MaxSectorsPerPacket;\r
+//        StorageAdapterDescriptor.MaximumTransferLength = SECTORSIZE * POOLSIZE;\r
+        StorageAdapterDescriptor.MaximumPhysicalPages = (ULONG)-1;\r
+        StorageAdapterDescriptor.AlignmentMask = 0;\r
+        StorageAdapterDescriptor.AdapterUsesPio = TRUE;\r
+        StorageAdapterDescriptor.AdapterScansDown = FALSE;\r
+        StorageAdapterDescriptor.CommandQueueing = FALSE;\r
+        StorageAdapterDescriptor.AcceleratedTransfer = FALSE;\r
+        StorageAdapterDescriptor.BusType = BusTypeScsi;\r
+        RtlCopyMemory(Irp->AssociatedIrp.SystemBuffer, &StorageAdapterDescriptor, CopySize);\r
+        Irp->IoStatus.Information = (ULONG_PTR)CopySize;\r
+        Status = STATUS_SUCCESS;\r
+      }\r
+\r
+      if (StoragePropertyQuery->PropertyId == StorageDeviceProperty && StoragePropertyQuery->QueryType == PropertyStandardQuery) {\r
+        CopySize = (Stack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(STORAGE_DEVICE_DESCRIPTOR)?Stack->Parameters.DeviceIoControl.OutputBufferLength:sizeof(STORAGE_DEVICE_DESCRIPTOR));\r
+        StorageDeviceDescriptor.Version = sizeof(STORAGE_DEVICE_DESCRIPTOR);\r
+        StorageDeviceDescriptor.Size = sizeof(STORAGE_DEVICE_DESCRIPTOR);\r
+        StorageDeviceDescriptor.DeviceType = DIRECT_ACCESS_DEVICE;\r
+        StorageDeviceDescriptor.DeviceTypeModifier = 0;\r
+        StorageDeviceDescriptor.RemovableMedia = FALSE;\r
+        StorageDeviceDescriptor.CommandQueueing = FALSE;\r
+        StorageDeviceDescriptor.VendorIdOffset = 0;\r
+        StorageDeviceDescriptor.ProductIdOffset = 0;\r
+        StorageDeviceDescriptor.ProductRevisionOffset = 0;\r
+        StorageDeviceDescriptor.SerialNumberOffset = 0;\r
+        StorageDeviceDescriptor.BusType = BusTypeScsi;\r
+        StorageDeviceDescriptor.RawPropertiesLength = 0;\r
+        RtlCopyMemory(Irp->AssociatedIrp.SystemBuffer, &StorageDeviceDescriptor, CopySize);\r
+        Irp->IoStatus.Information = (ULONG_PTR)CopySize;\r
+        Status = STATUS_SUCCESS;\r
+      }\r
+\r
+      if (Status == STATUS_INVALID_PARAMETER) {\r
+        DbgPrint("!!Invalid IOCTL_STORAGE_QUERY_PROPERTY (PropertyId: %08x / QueryType: %08x)!!\n", StoragePropertyQuery->PropertyId, StoragePropertyQuery->QueryType);\r
+      }\r
+      break;\r
+    case IOCTL_DISK_GET_DRIVE_GEOMETRY:\r
+      CopySize = (Stack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(DISK_GEOMETRY)?Stack->Parameters.DeviceIoControl.OutputBufferLength:sizeof(DISK_GEOMETRY));\r
+      DiskGeometry.MediaType = FixedMedia;\r
+      DiskGeometry.Cylinders.QuadPart = DeviceExtension->Disk.Cylinders;\r
+      DiskGeometry.TracksPerCylinder = DeviceExtension->Disk.Heads;\r
+      DiskGeometry.SectorsPerTrack = DeviceExtension->Disk.Sectors;\r
+      DiskGeometry.BytesPerSector = SECTORSIZE;\r
+      RtlCopyMemory(Irp->AssociatedIrp.SystemBuffer, &DiskGeometry, CopySize);\r
+      Irp->IoStatus.Information = (ULONG_PTR)CopySize;\r
+      Status = STATUS_SUCCESS;\r
+      break;\r
+    case IOCTL_SCSI_GET_ADDRESS:\r
+      CopySize = (Stack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(SCSI_ADDRESS)?Stack->Parameters.DeviceIoControl.OutputBufferLength:sizeof(SCSI_ADDRESS));\r
+      ScsiAdress.Length = sizeof(SCSI_ADDRESS);\r
+      ScsiAdress.PortNumber = 0;\r
+      ScsiAdress.PathId = 0;\r
+      ScsiAdress.TargetId = (UCHAR)DeviceExtension->Disk.DiskNumber;\r
+      ScsiAdress.Lun = 0;\r
+      RtlCopyMemory(Irp->AssociatedIrp.SystemBuffer, &ScsiAdress, CopySize);\r
+      Irp->IoStatus.Information = (ULONG_PTR)CopySize;\r
+      Status = STATUS_SUCCESS;\r
+      break;\r
+    default:\r
+      Irp->IoStatus.Information = 0;\r
+      Status = STATUS_INVALID_PARAMETER;\r
+  }\r
+\r
+  Irp->IoStatus.Status = Status;\r
+  IoCompleteRequest(Irp, IO_NO_INCREMENT);\r
+  return Status;\r
+}\r
+\r
+NTSTATUS STDCALL DiskDispatchSystemControl(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PIO_STACK_LOCATION Stack, IN PDEVICEEXTENSION DeviceExtension) {\r
+  NTSTATUS Status;\r
+\r
+  Status = Irp->IoStatus.Status;\r
+  IoCompleteRequest(Irp, IO_NO_INCREMENT);\r
+  return Status;\r
+}\r
+\r
+// FIXME put in SCSI\r
+NTSTATUS STDCALL BusGetDeviceCapabilities(IN PDEVICE_OBJECT DeviceObject, IN PDEVICE_CAPABILITIES DeviceCapabilities) {\r
+  IO_STATUS_BLOCK ioStatus;\r
+  KEVENT pnpEvent;\r
+  NTSTATUS status;\r
+  PDEVICE_OBJECT targetObject;\r
+  PIO_STACK_LOCATION irpStack;\r
+  PIRP pnpIrp;\r
+\r
+  RtlZeroMemory(DeviceCapabilities, sizeof(DEVICE_CAPABILITIES));\r
+  DeviceCapabilities->Size = sizeof(DEVICE_CAPABILITIES);\r
+  DeviceCapabilities->Version = 1;\r
+  DeviceCapabilities->Address = -1;\r
+  DeviceCapabilities->UINumber = -1;\r
+\r
+  KeInitializeEvent(&pnpEvent, NotificationEvent, FALSE);\r
+  targetObject = IoGetAttachedDeviceReference(DeviceObject);\r
+  pnpIrp = IoBuildSynchronousFsdRequest(IRP_MJ_PNP, targetObject, NULL, 0, NULL, &pnpEvent, &ioStatus);\r
+  if (pnpIrp == NULL) {\r
+    status = STATUS_INSUFFICIENT_RESOURCES;\r
+  } else {\r
+    pnpIrp->IoStatus.Status = STATUS_NOT_SUPPORTED;\r
+    irpStack = IoGetNextIrpStackLocation(pnpIrp);\r
+    RtlZeroMemory(irpStack, sizeof(IO_STACK_LOCATION));\r
+    irpStack->MajorFunction = IRP_MJ_PNP;\r
+    irpStack->MinorFunction = IRP_MN_QUERY_CAPABILITIES;\r
+    irpStack->Parameters.DeviceCapabilities.Capabilities = DeviceCapabilities;\r
+    status = IoCallDriver(targetObject, pnpIrp);\r
+    if (status == STATUS_PENDING) {\r
+      KeWaitForSingleObject(&pnpEvent, Executive, KernelMode, FALSE, NULL);\r
+      status = ioStatus.Status;\r
+    }\r
+  }\r
+  ObDereferenceObject(targetObject);\r
+  return status;\r
+}\r
diff --git a/src/driver.c b/src/driver.c
new file mode 100644 (file)
index 0000000..46604ac
--- /dev/null
@@ -0,0 +1,200 @@
+/*\r
+  Copyright 2006-2008, V.\r
+  For contact information, see http://winaoe.org/\r
+\r
+  This file is part of WinAoE.\r
+\r
+  WinAoE is free software: you can redistribute it and/or modify\r
+  it under the terms of the GNU General Public License as published by\r
+  the Free Software Foundation, either version 3 of the License, or\r
+  (at your option) any later version.\r
+\r
+  WinAoE is distributed in the hope that it will be useful,\r
+  but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+  GNU General Public License for more details.\r
+\r
+  You should have received a copy of the GNU General Public License\r
+  along with WinAoE.  If not, see <http://www.gnu.org/licenses/>.\r
+*/\r
+\r
+#include "portable.h"\r
+#include <ntddk.h>\r
+#include "driver.h"\r
+\r
+// from registry.c\r
+NTSTATUS STDCALL CheckRegistry();\r
+\r
+// from bus.c\r
+NTSTATUS STDCALL BusStart();\r
+VOID STDCALL BusStop();\r
+NTSTATUS STDCALL BusAddDevice(IN PDRIVER_OBJECT DriverObject, IN PDEVICE_OBJECT PhysicalDeviceObject);\r
+NTSTATUS STDCALL BusDispatchPnP(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PIO_STACK_LOCATION Stack, IN PDEVICEEXTENSION DeviceExtension);\r
+NTSTATUS STDCALL BusDispatchDeviceControl(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PIO_STACK_LOCATION Stack, IN PDEVICEEXTENSION DeviceExtension);\r
+NTSTATUS STDCALL BusDispatchSystemControl(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PIO_STACK_LOCATION Stack, IN PDEVICEEXTENSION DeviceExtension);\r
+\r
+// from disk.c\r
+NTSTATUS STDCALL DiskDispatchPnP(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PIO_STACK_LOCATION Stack, IN PDEVICEEXTENSION DeviceExtension);\r
+NTSTATUS STDCALL DiskDispatchSCSI(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PIO_STACK_LOCATION Stack, IN PDEVICEEXTENSION DeviceExtension);\r
+NTSTATUS STDCALL DiskDispatchDeviceControl(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PIO_STACK_LOCATION Stack, IN PDEVICEEXTENSION DeviceExtension);\r
+NTSTATUS STDCALL DiskDispatchSystemControl(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PIO_STACK_LOCATION Stack, IN PDEVICEEXTENSION DeviceExtension);\r
+\r
+// from aoe.c\r
+NTSTATUS STDCALL AoEStart();\r
+VOID STDCALL AoEStop();\r
+\r
+// from protocol.c\r
+NTSTATUS STDCALL ProtocolStart();\r
+VOID STDCALL ProtocolStop();\r
+\r
+// from debug.c\r
+VOID STDCALL InitializeDebug();\r
+VOID STDCALL DebugIrpStart(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp);\r
+VOID STDCALL DebugIrpEnd(IN PIRP Irp, IN NTSTATUS Status);\r
+\r
+// in this file\r
+NTSTATUS STDCALL DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath);\r
+NTSTATUS STDCALL Dispatch(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp);\r
+VOID STDCALL Unload(IN PDRIVER_OBJECT DriverObject);\r
+\r
+PVOID StateHandle;\r
+\r
+NTSTATUS STDCALL DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath) {\r
+  NTSTATUS Status;\r
+  int i;\r
+\r
+//---\r
+//---\r
+\r
+  DbgPrint("DriverEntry\n");\r
+  InitializeDebug();\r
+  if (!NT_SUCCESS(Status = CheckRegistry())) return Error("CheckRegistry", Status);\r
+  if (!NT_SUCCESS(Status = BusStart())) return Error("BusStart", Status);\r
+  if (!NT_SUCCESS(Status = AoEStart())) {\r
+    BusStop();\r
+    return Error("AoEStart", Status);\r
+  }\r
+  if (!NT_SUCCESS(Status = ProtocolStart())) {\r
+    AoEStop();\r
+    BusStop();\r
+    return Error("ProtocolStart", Status);\r
+  }\r
+\r
+  StateHandle = NULL;\r
+  if ((StateHandle = PoRegisterSystemState(NULL, ES_CONTINUOUS)) == NULL) {\r
+    DbgPrint("Could not set system state to ES_CONTINUOUS!!\n");\r
+  }\r
+\r
+  for (i = 0; i <= IRP_MJ_MAXIMUM_FUNCTION; i++) DriverObject->MajorFunction[i] = Dispatch;\r
+  DriverObject->DriverExtension->AddDevice = BusAddDevice;\r
+  DriverObject->MajorFunction[IRP_MJ_PNP] = Dispatch;\r
+  DriverObject->MajorFunction[IRP_MJ_POWER] = Dispatch;\r
+  DriverObject->MajorFunction[IRP_MJ_CREATE] = Dispatch;\r
+  DriverObject->MajorFunction[IRP_MJ_CLOSE] = Dispatch;\r
+  DriverObject->MajorFunction[IRP_MJ_SYSTEM_CONTROL] = Dispatch;\r
+  DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = Dispatch;\r
+  DriverObject->MajorFunction[IRP_MJ_SCSI] = Dispatch;\r
+  DriverObject->DriverUnload = Unload;\r
+\r
+#ifdef RIS\r
+  IoReportDetectedDevice(DriverObject, InterfaceTypeUndefined, -1, -1, NULL, NULL, FALSE, &PDODeviceObject);\r
+  if (!NT_SUCCESS(Status = BusAddDevice(DriverObject, PDODeviceObject))) {\r
+    ProtocolStop();\r
+    AoEStop();\r
+    Error("AddDevice", Status);\r
+  }\r
+  return Status;\r
+#else\r
+  return STATUS_SUCCESS;\r
+#endif\r
+}\r
+\r
+NTSTATUS STDCALL Dispatch(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp) {\r
+  NTSTATUS Status;\r
+  PIO_STACK_LOCATION Stack;\r
+  PDEVICEEXTENSION DeviceExtension;\r
+\r
+#ifdef DEBUGIRPS\r
+  DebugIrpStart(DeviceObject, Irp);\r
+#endif\r
+  Stack = IoGetCurrentIrpStackLocation(Irp);\r
+  DeviceExtension = (PDEVICEEXTENSION)DeviceObject->DeviceExtension;\r
+\r
+  if (DeviceExtension->State == Deleted) {\r
+    if (Stack->MajorFunction == IRP_MJ_POWER) PoStartNextPowerIrp(Irp);\r
+    Irp->IoStatus.Information = 0;\r
+    Irp->IoStatus.Status = STATUS_NO_SUCH_DEVICE;\r
+    IoCompleteRequest(Irp, IO_NO_INCREMENT);\r
+#ifdef DEBUGIRPS\r
+    DebugIrpEnd(Irp, STATUS_NO_SUCH_DEVICE);\r
+#endif\r
+    return STATUS_NO_SUCH_DEVICE;\r
+  }\r
+\r
+  switch (Stack->MajorFunction) {\r
+    case IRP_MJ_POWER:\r
+      if (DeviceExtension->IsBus) {\r
+        PoStartNextPowerIrp(Irp);\r
+        IoSkipCurrentIrpStackLocation(Irp);\r
+        Status = PoCallDriver(DeviceExtension->Bus.LowerDeviceObject, Irp);\r
+      } else {\r
+        PoStartNextPowerIrp(Irp);\r
+        Irp->IoStatus.Status = STATUS_NOT_SUPPORTED;\r
+        IoCompleteRequest(Irp, IO_NO_INCREMENT);\r
+        Status = STATUS_NOT_SUPPORTED;\r
+      }\r
+      break;\r
+    case IRP_MJ_PNP:\r
+      if (DeviceExtension->IsBus) Status = BusDispatchPnP(DeviceObject, Irp, Stack, DeviceExtension);\r
+      else Status = DiskDispatchPnP(DeviceObject, Irp, Stack, DeviceExtension);\r
+      break;\r
+    case IRP_MJ_SYSTEM_CONTROL:\r
+      if (DeviceExtension->IsBus) Status = BusDispatchSystemControl(DeviceObject, Irp, Stack, DeviceExtension);\r
+      else Status = DiskDispatchSystemControl(DeviceObject, Irp, Stack, DeviceExtension);\r
+      break;\r
+    case IRP_MJ_DEVICE_CONTROL:\r
+      if (DeviceExtension->IsBus) Status = BusDispatchDeviceControl(DeviceObject, Irp, Stack, DeviceExtension);\r
+      else Status = DiskDispatchDeviceControl(DeviceObject, Irp, Stack, DeviceExtension);\r
+      break;\r
+    case IRP_MJ_CREATE:\r
+    case IRP_MJ_CLOSE:\r
+      Status = STATUS_SUCCESS;\r
+      Irp->IoStatus.Status = Status;\r
+      IoCompleteRequest(Irp, IO_NO_INCREMENT);\r
+      break;\r
+    case IRP_MJ_SCSI:\r
+      if (!DeviceExtension->IsBus) {\r
+        Status = DiskDispatchSCSI(DeviceObject, Irp, Stack, DeviceExtension);\r
+        break;\r
+      }\r
+    default:\r
+      Status = STATUS_NOT_SUPPORTED;\r
+      Irp->IoStatus.Status = Status;\r
+      IoCompleteRequest(Irp, IO_NO_INCREMENT);\r
+  }\r
+\r
+#ifdef DEBUGIRPS\r
+  if (Status != STATUS_PENDING) DebugIrpEnd(Irp, Status);\r
+#endif\r
+  return Status;\r
+}\r
+\r
+VOID STDCALL Unload(IN PDRIVER_OBJECT DriverObject) {\r
+  if (StateHandle != NULL) PoUnregisterSystemState(StateHandle);\r
+  ProtocolStop();\r
+  AoEStop();\r
+  BusStop();\r
+  DbgPrint("Unload\n");\r
+}\r
+\r
+VOID STDCALL CompletePendingIrp(IN PIRP Irp) {\r
+#ifdef DEBUGIRPS\r
+  DebugIrpEnd(Irp, Irp->IoStatus.Status);\r
+#endif\r
+  IoCompleteRequest(Irp, IO_NO_INCREMENT);\r
+}\r
+\r
+NTSTATUS STDCALL Error(IN PCHAR Message, IN NTSTATUS Status) {\r
+  DbgPrint("%s: 0x%08x\n", Message, Status);\r
+  return Status;\r
+}\r
diff --git a/src/driver.h b/src/driver.h
new file mode 100644 (file)
index 0000000..14f2c02
--- /dev/null
@@ -0,0 +1,81 @@
+/*\r
+  Copyright 2006-2008, V.\r
+  For contact information, see http://winaoe.org/\r
+\r
+  This file is part of WinAoE.\r
+\r
+  WinAoE is free software: you can redistribute it and/or modify\r
+  it under the terms of the GNU General Public License as published by\r
+  the Free Software Foundation, either version 3 of the License, or\r
+  (at your option) any later version.\r
+\r
+  WinAoE is distributed in the hope that it will be useful,\r
+  but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+  GNU General Public License for more details.\r
+\r
+  You should have received a copy of the GNU General Public License\r
+  along with WinAoE.  If not, see <http://www.gnu.org/licenses/>.\r
+*/\r
+\r
+#ifndef _DRIVER_H\r
+#define _DRIVER_H\r
+#include "portable.h"\r
+\r
+//#define RIS\r
+\r
+//#define DEBUGIRPS\r
+//#define DEBUGMOSTPROTOCOLCALLS\r
+//#define DEBUGALLPROTOCOLCALLS\r
+\r
+#define AOEPROTOCOLID 0x88a2\r
+#define AOEPROTOCOLVER 1\r
+#define SECTORSIZE 512\r
+#define POOLSIZE 2048\r
+\r
+typedef enum {NotStarted, Started, StopPending, Stopped, RemovePending, SurpriseRemovePending, Deleted} STATE, *PSTATE;\r
+typedef enum {SearchNIC, GetSize, GettingSize, GetGeometry, GettingGeometry, GetMaxSectorsPerPacket, GettingMaxSectorsPerPacket, Done} SEARCHSTATE, *PSEARCHSTATE;\r
+\r
+typedef struct _DEVICEEXTENSION {\r
+  BOOLEAN IsBus;\r
+  PDEVICE_OBJECT Self;\r
+  PDRIVER_OBJECT DriverObject;\r
+  STATE State;\r
+  STATE OldState;\r
+  union {\r
+    struct {\r
+      PDEVICE_OBJECT LowerDeviceObject;\r
+      PDEVICE_OBJECT PhysicalDeviceObject;\r
+      ULONG Children;\r
+      struct _DEVICEEXTENSION *ChildList;\r
+      KSPIN_LOCK SpinLock;\r
+    } Bus;\r
+    struct {\r
+      PDEVICE_OBJECT Parent;\r
+      struct _DEVICEEXTENSION *Next;\r
+      KEVENT SearchEvent;\r
+      SEARCHSTATE SearchState;\r
+      KSPIN_LOCK SpinLock;\r
+      BOOLEAN BootDrive;\r
+      BOOLEAN Unmount;\r
+      ULONG DiskNumber;\r
+      ULONG MTU;\r
+      UCHAR ClientMac[6];\r
+      UCHAR ServerMac[6];\r
+      ULONG Major;\r
+      ULONG Minor;\r
+      LONGLONG LBADiskSize;\r
+      LONGLONG Cylinders;\r
+      ULONG Heads;\r
+      ULONG Sectors;\r
+      ULONG MaxSectorsPerPacket;\r
+      ULONG SpecialFileCount;\r
+      ULONG Timeout;\r
+    } Disk;\r
+  };\r
+} DEVICEEXTENSION, *PDEVICEEXTENSION;\r
+\r
+VOID STDCALL CompletePendingIrp(IN PIRP Irp);\r
+NTSTATUS STDCALL Error(IN PCHAR Message, IN NTSTATUS Status);\r
+\r
+#endif\r
diff --git a/src/loader.c b/src/loader.c
new file mode 100644 (file)
index 0000000..57d79c4
--- /dev/null
@@ -0,0 +1,106 @@
+/*\r
+  Copyright 2006-2008, V.\r
+  For contact information, see http://winaoe.org/\r
+\r
+  This file is part of WinAoE.\r
+\r
+  WinAoE is free software: you can redistribute it and/or modify\r
+  it under the terms of the GNU General Public License as published by\r
+  the Free Software Foundation, either version 3 of the License, or\r
+  (at your option) any later version.\r
+\r
+  WinAoE is distributed in the hope that it will be useful,\r
+  but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+  GNU General Public License for more details.\r
+\r
+  You should have received a copy of the GNU General Public License\r
+  along with WinAoE.  If not, see <http://www.gnu.org/licenses/>.\r
+*/\r
+\r
+#include "portable.h"\r
+#include <stdio.h>\r
+#include <windows.h>\r
+#include <Setupapi.h>\r
+#include <newdev.h>\r
+\r
+#define MAX_CLASS_NAME_LEN 64\r
+\r
+//typedef BOOL WINAPI (*PROC)(HWND, LPCTSTR, LPCTSTR, DWORD, PBOOL OPTIONAL);\r
+\r
+void DisplayError(char *String) {\r
+  CHAR ErrorString[1024];\r
+  UINT ErrorCode = GetLastError();\r
+\r
+  printf("Error: %s\n", String);\r
+  printf("GetLastError: 0x%08x (%d)\n", ErrorCode, (int)ErrorCode);\r
+  if (FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, ErrorCode, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)ErrorString, sizeof(ErrorString), NULL)) printf("%s", ErrorString);\r
+}\r
+\r
+int main(int argc, char **argv, char **envp) {\r
+  HDEVINFO DeviceInfoSet = 0;\r
+  SP_DEVINFO_DATA DeviceInfoData;\r
+  GUID ClassGUID;\r
+  TCHAR ClassName[MAX_CLASS_NAME_LEN];\r
+  HINSTANCE Library;\r
+  PROC UpdateDriverForPlugAndPlayDevicesA;\r
+  BOOL RebootRequired = FALSE;\r
+  TCHAR FullFilePath[1024];\r
+\r
+  if (!GetFullPathName("aoe.inf", sizeof(FullFilePath), FullFilePath, NULL)) goto GetFullPathNameError;\r
+  if ((Library = LoadLibrary("newdev.dll")) == NULL) goto LoadLibraryError;\r
+  if ((UpdateDriverForPlugAndPlayDevicesA = GetProcAddress(Library, "UpdateDriverForPlugAndPlayDevicesA")) == NULL) goto GetProcAddressError;\r
+\r
+  if (!SetupDiGetINFClass(FullFilePath, &ClassGUID, ClassName, sizeof(ClassName), 0)) goto GetINFClassError;\r
+  if ((DeviceInfoSet = SetupDiCreateDeviceInfoList(&ClassGUID, 0)) == INVALID_HANDLE_VALUE) goto CreateDeviceInfoListError;\r
+  DeviceInfoData.cbSize = sizeof(SP_DEVINFO_DATA);\r
+  if (!SetupDiCreateDeviceInfo(DeviceInfoSet, ClassName, &ClassGUID, NULL, 0, DICD_GENERATE_ID, &DeviceInfoData)) goto CreateDeviceInfoError;\r
+  if (!SetupDiSetDeviceRegistryProperty(DeviceInfoSet, &DeviceInfoData, SPDRP_HARDWAREID, (LPBYTE)"AoE\0\0\0", (lstrlen("AoE\0\0\0")+1+1) * sizeof(TCHAR))) goto SetDeviceRegistryPropertyError;\r
+  if (!SetupDiCallClassInstaller(DIF_REGISTERDEVICE, DeviceInfoSet, &DeviceInfoData)) goto CallClassInstallerREGISTERDEVICEError;\r
+\r
+  if (!UpdateDriverForPlugAndPlayDevices(0, "AoE\0\0\0", FullFilePath, INSTALLFLAG_FORCE, &RebootRequired)) {\r
+    DWORD err = GetLastError();\r
+    DisplayError("UpdateDriverForPlugAndPlayDevices");\r
+    if (!SetupDiCallClassInstaller(DIF_REMOVE, DeviceInfoSet, &DeviceInfoData)) DisplayError("CallClassInstaller(REMOVE)");\r
+    SetLastError(err);\r
+  }\r
+  if (RebootRequired) printf("Need reboot\n");\r
+\r
+  printf("Press enter to remove\n");\r
+  getchar();\r
+  if (!SetupDiCallClassInstaller(DIF_REMOVE, DeviceInfoSet, &DeviceInfoData)) DisplayError("CallClassInstaller(REMOVE)");\r
+  return 0;\r
+\r
+GetFullPathNameError:\r
+  DisplayError("GetFullPathName");\r
+  goto end;\r
+LoadLibraryError:\r
+  DisplayError("LoadLibrary");\r
+  goto end;\r
+GetProcAddressError:\r
+  DisplayError("GetProcAddress");\r
+  goto end;\r
+GetINFClassError:\r
+  DisplayError("GetINFClass");\r
+  goto end;\r
+CreateDeviceInfoListError:\r
+  DisplayError("CreateDeviceInfoList");\r
+  goto end;\r
+\r
+CreateDeviceInfoError:\r
+  DisplayError("CreateDeviceInfo");\r
+  goto cleanup_DeviceInfo;\r
+SetDeviceRegistryPropertyError:\r
+  DisplayError("SetDeviceRegistryProperty");\r
+  goto cleanup_DeviceInfo;\r
+CallClassInstallerREGISTERDEVICEError:\r
+  DisplayError("CallClassInstaller(REGISTERDEVICE)");\r
+  goto cleanup_DeviceInfo;\r
+\r
+cleanup_DeviceInfo:\r
+  SetupDiDestroyDeviceInfoList(DeviceInfoSet);\r
+end:\r
+  printf("Press enter to exit\n");\r
+  getchar();\r
+  return 0;\r
+}\r
diff --git a/src/mount.c b/src/mount.c
new file mode 100644 (file)
index 0000000..6d7f3d5
--- /dev/null
@@ -0,0 +1,150 @@
+/*\r
+  Copyright 2006-2008, V.\r
+  For contact information, see http://winaoe.org/\r
+\r
+  This file is part of WinAoE.\r
+\r
+  WinAoE is free software: you can redistribute it and/or modify\r
+  it under the terms of the GNU General Public License as published by\r
+  the Free Software Foundation, either version 3 of the License, or\r
+  (at your option) any later version.\r
+\r
+  WinAoE is distributed in the hope that it will be useful,\r
+  but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+  GNU General Public License for more details.\r
+\r
+  You should have received a copy of the GNU General Public License\r
+  along with WinAoE.  If not, see <http://www.gnu.org/licenses/>.\r
+*/\r
+\r
+#include "portable.h"\r
+#include <windows.h>\r
+#include <winioctl.h>\r
+#include <stdio.h>\r
+#include "mount.h"\r
+\r
+typedef enum {CommandScan, CommandShow, CommandMount, CommandUmount} COMMAND;\r
+\r
+void Help() {\r
+  printf("aoe <scan|show|mount|umount>\n\n");\r
+  printf("  scan\n        Shows the reachable AoE targets.\n\n");\r
+  printf("  show\n        Shows the mounted AoE targets.\n\n");\r
+  printf("  mount <client mac address> <major> <minor>\n        Mounts an AoE target.\n\n");\r
+  printf("  umount <disk number>\n        Unmounts an AoE disk.\n\n");\r
+}\r
+\r
+int main(int argc, char **argv, char **envp) {\r
+  COMMAND Command;\r
+  HANDLE DeviceHandle;\r
+  UCHAR InBuffer[1024];\r
+  UCHAR String[256];\r
+  PTARGETS Targets;\r
+  PDISKS Disks;\r
+  UCHAR Mac[6];\r
+  DWORD BytesReturned;\r
+  ULONG Major, Minor, Disk;\r
+  ULONG i;\r
+\r
+  if (argc < 2) {\r
+    Help();\r
+    goto end;\r
+  }\r
+\r
+  if (strcmp(argv[1], "scan") == 0) {\r
+    Command = CommandScan;\r
+  } else if (strcmp(argv[1], "show") == 0) {\r
+    Command = CommandShow;\r
+  } else if (strcmp(argv[1], "mount") == 0) {\r
+    Command = CommandMount;\r
+  } else if (strcmp(argv[1], "umount") == 0) {\r
+    Command = CommandUmount;\r
+  } else {\r
+    Help();\r
+    printf("Press enter to exit\n");\r
+    getchar();\r
+    goto end;\r
+  }\r
+\r
+  DeviceHandle = CreateFile("\\\\.\\AoE", GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);\r
+  if (DeviceHandle == INVALID_HANDLE_VALUE) {\r
+    printf("CreateFile (%d)\n", (int)GetLastError());\r
+    goto end;\r
+  }\r
+\r
+  switch (Command) {\r
+    case CommandScan:\r
+      if ((Targets = (PTARGETS)malloc(sizeof(TARGETS) + (32 * sizeof(TARGET)))) == NULL) {\r
+        printf("Out of memory\n");\r
+        break;\r
+      }\r
+      if (!DeviceIoControl(DeviceHandle, IOCTL_AOE_SCAN, NULL, 0, Targets, (sizeof(TARGETS) + (32 * sizeof(TARGET))), &BytesReturned, (LPOVERLAPPED) NULL)) {\r
+        printf("DeviceIoControl (%d)\n", (int)GetLastError());\r
+        free(Targets);\r
+        break;\r
+      }\r
+      if (Targets->Count == 0) {\r
+        printf("No AoE targets found.\n");\r
+      } else {\r
+        printf("Client NIC          Target      Server MAC         Size\n");\r
+        for (i = 0; i < Targets->Count && i < 10; i++) {\r
+          sprintf(String, "e%lu.%lu      ", Targets->Target[i].Major, Targets->Target[i].Minor);\r
+          String[10] = 0;\r
+          printf(" %02x:%02x:%02x:%02x:%02x:%02x  %s  %02x:%02x:%02x:%02x:%02x:%02x  %I64uM\n", Targets->Target[i].ClientMac[0], Targets->Target[i].ClientMac[1], Targets->Target[i].ClientMac[2], Targets->Target[i].ClientMac[3], Targets->Target[i].ClientMac[4], Targets->Target[i].ClientMac[5], String, Targets->Target[i].ServerMac[0], Targets->Target[i].ServerMac[1], Targets->Target[i].ServerMac[2], Targets->Target[i].ServerMac[3], Targets->Target[i].ServerMac[4], Targets->Target[i].ServerMac[5], (Targets->Target[i].LBASize / 2048));\r
+        }\r
+      }\r
+      free(Targets);\r
+      printf("Press enter to exit\n");\r
+      getchar();\r
+      break;\r
+    case CommandShow:\r
+      if ((Disks = (PDISKS)malloc(sizeof(DISKS) + (32 * sizeof(DISK)))) == NULL) {\r
+        printf("Out of memory\n");\r
+        break;\r
+      }\r
+      if (!DeviceIoControl(DeviceHandle, IOCTL_AOE_SHOW, NULL, 0, Disks, (sizeof(DISKS) + (32 * sizeof(DISK))), &BytesReturned, (LPOVERLAPPED) NULL)) {\r
+        printf("DeviceIoControl (%d)\n", (int)GetLastError());\r
+        free(Disks);\r
+        break;\r
+      }\r
+      if (Disks->Count == 0) {\r
+        printf("No AoE disks mounted.\n");\r
+      } else {\r
+        printf("Disk  Client NIC         Server MAC         Target      Size\n");\r
+        for (i = 0; i < Disks->Count && i < 10; i++) {\r
+          sprintf(String, "e%lu.%lu      ", Disks->Disk[i].Major, Disks->Disk[i].Minor);\r
+          String[10] = 0;\r
+          printf(" %-4lu %02x:%02x:%02x:%02x:%02x:%02x  %02x:%02x:%02x:%02x:%02x:%02x  %s  %I64uM\n", Disks->Disk[i].Disk, Disks->Disk[i].ClientMac[0], Disks->Disk[i].ClientMac[1], Disks->Disk[i].ClientMac[2], Disks->Disk[i].ClientMac[3], Disks->Disk[i].ClientMac[4], Disks->Disk[i].ClientMac[5], Disks->Disk[i].ServerMac[0], Disks->Disk[i].ServerMac[1], Disks->Disk[i].ServerMac[2], Disks->Disk[i].ServerMac[3], Disks->Disk[i].ServerMac[4], Disks->Disk[i].ServerMac[5], String, (Disks->Disk[i].LBASize / 2048));\r
+        }\r
+      }\r
+      free(Disks);\r
+      printf("Press enter to exit\n");\r
+      getchar();\r
+      break;\r
+    case CommandMount:\r
+      sscanf(argv[2], "%02x:%02x:%02x:%02x:%02x:%02x", (int*)&Mac[0], (int*)&Mac[1], (int*)&Mac[2], (int*)&Mac[3], (int*)&Mac[4], (int*)&Mac[5]);\r
+      sscanf(argv[3], "%d", (int*)&Major);\r
+      sscanf(argv[4], "%d", (int*)&Minor);\r
+      printf("mounting e%d.%d from %02x:%02x:%02x:%02x:%02x:%02x\n", (int)Major, (int)Minor, Mac[0], Mac[1], Mac[2], Mac[3], Mac[4], Mac[5]);\r
+      memcpy(&InBuffer[0], Mac, 6);\r
+      *(PUSHORT)(&InBuffer[6]) = (USHORT)Major;\r
+      *(PUCHAR)(&InBuffer[8]) = (UCHAR)Minor;\r
+      if (!DeviceIoControl(DeviceHandle, IOCTL_AOE_MOUNT, InBuffer, sizeof(InBuffer), NULL, 0, &BytesReturned, (LPOVERLAPPED) NULL)) {\r
+        printf("DeviceIoControl (%d)\n", (int)GetLastError());\r
+      }\r
+      break;\r
+    case CommandUmount:\r
+      sscanf(argv[2], "%d", (int*)&Disk);\r
+      printf("unmounting disk %d\n", (int)Disk);\r
+      memcpy(&InBuffer, &Disk, 4);\r
+      if (!DeviceIoControl(DeviceHandle, IOCTL_AOE_UMOUNT, InBuffer, sizeof(InBuffer), NULL, 0, &BytesReturned, (LPOVERLAPPED) NULL)) {\r
+        printf("DeviceIoControl (%d)\n", (int)GetLastError());\r
+      }\r
+      break;\r
+  }\r
+\r
+  CloseHandle(DeviceHandle);\r
+\r
+end:\r
+  return 0;\r
+}\r
diff --git a/src/mount.h b/src/mount.h
new file mode 100644 (file)
index 0000000..4577f85
--- /dev/null
@@ -0,0 +1,58 @@
+/*\r
+  Copyright 2006-2008, V.\r
+  For contact information, see http://winaoe.org/\r
+\r
+  This file is part of WinAoE.\r
+\r
+  WinAoE is free software: you can redistribute it and/or modify\r
+  it under the terms of the GNU General Public License as published by\r
+  the Free Software Foundation, either version 3 of the License, or\r
+  (at your option) any later version.\r
+\r
+  WinAoE is distributed in the hope that it will be useful,\r
+  but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+  GNU General Public License for more details.\r
+\r
+  You should have received a copy of the GNU General Public License\r
+  along with WinAoE.  If not, see <http://www.gnu.org/licenses/>.\r
+*/\r
+\r
+#ifndef _MOUNT_H\r
+#define _MOUNT_H\r
+#include "portable.h"\r
+\r
+#define IOCTL_AOE_SCAN CTL_CODE(FILE_DEVICE_CONTROLLER, 0x800, METHOD_BUFFERED, FILE_READ_DATA | FILE_WRITE_DATA)\r
+#define IOCTL_AOE_SHOW CTL_CODE(FILE_DEVICE_CONTROLLER, 0x801, METHOD_BUFFERED, FILE_READ_DATA | FILE_WRITE_DATA)\r
+#define IOCTL_AOE_MOUNT CTL_CODE(FILE_DEVICE_CONTROLLER, 0x802, METHOD_BUFFERED, FILE_READ_DATA | FILE_WRITE_DATA)\r
+#define IOCTL_AOE_UMOUNT CTL_CODE(FILE_DEVICE_CONTROLLER, 0x803, METHOD_BUFFERED, FILE_READ_DATA | FILE_WRITE_DATA)\r
+\r
+typedef struct _TARGET {\r
+  UCHAR ClientMac[6];\r
+  UCHAR ServerMac[6];\r
+  ULONG Major;\r
+  ULONG Minor;\r
+  LONGLONG LBASize;\r
+  LARGE_INTEGER ProbeTime;\r
+} TARGET, *PTARGET;\r
+\r
+typedef struct _TARGETS {\r
+  ULONG Count;\r
+  TARGET Target[];\r
+} TARGETS, *PTARGETS;\r
+\r
+typedef struct _DISK {\r
+  ULONG Disk;\r
+  UCHAR ClientMac[6];\r
+  UCHAR ServerMac[6];\r
+  ULONG Major;\r
+  ULONG Minor;\r
+  LONGLONG LBASize;\r
+} DISK, *PDISK;\r
+\r
+typedef struct _DISKS {\r
+  ULONG Count;\r
+  DISK Disk[];\r
+} DISKS, *PDISKS;\r
+\r
+#endif\r
diff --git a/src/portable.h b/src/portable.h
new file mode 100644 (file)
index 0000000..881911f
--- /dev/null
@@ -0,0 +1,40 @@
+/*\r
+  Copyright 2006-2008, V.\r
+  For contact information, see http://winaoe.org/\r
+\r
+  This file is part of WinAoE.\r
+\r
+  WinAoE is free software: you can redistribute it and/or modify\r
+  it under the terms of the GNU General Public License as published by\r
+  the Free Software Foundation, either version 3 of the License, or\r
+  (at your option) any later version.\r
+\r
+  WinAoE is distributed in the hope that it will be useful,\r
+  but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+  GNU General Public License for more details.\r
+\r
+  You should have received a copy of the GNU General Public License\r
+  along with WinAoE.  If not, see <http://www.gnu.org/licenses/>.\r
+*/\r
+\r
+#ifndef _PORTABLE_H\r
+#define _PORTABLE_H\r
+\r
+#define NDIS50 1\r
+#define OBJ_KERNEL_HANDLE 0x00000200L\r
+#ifdef _MSC_VER\r
+#define STDCALL\r
+#define __attribute__(x)\r
+typedef unsigned int UINT, *PUINT;\r
+#endif\r
+\r
+#if _WIN32_WINNT < 0x0502\r
+#define SCSIOP_READ16 0x88\r
+#define SCSIOP_WRITE16 0x8a\r
+#define SCSIOP_VERIFY16 0x8f\r
+#define SCSIOP_READ_CAPACITY16 0x9e\r
+#endif\r
+\r
+#endif\r
+\r
diff --git a/src/protocol.c b/src/protocol.c
new file mode 100644 (file)
index 0000000..eaf7e35
--- /dev/null
@@ -0,0 +1,579 @@
+/*\r
+  Copyright 2006-2008, V.\r
+  For contact information, see http://winaoe.org/\r
+\r
+  This file is part of WinAoE.\r
+\r
+  WinAoE is free software: you can redistribute it and/or modify\r
+  it under the terms of the GNU General Public License as published by\r
+  the Free Software Foundation, either version 3 of the License, or\r
+  (at your option) any later version.\r
+\r
+  WinAoE is distributed in the hope that it will be useful,\r
+  but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+  GNU General Public License for more details.\r
+\r
+  You should have received a copy of the GNU General Public License\r
+  along with WinAoE.  If not, see <http://www.gnu.org/licenses/>.\r
+*/\r
+\r
+#include "portable.h"\r
+#include <ntddk.h>\r
+#include <ndis.h>\r
+#include <ntddndis.h>\r
+#include "protocol.h"\r
+#include "driver.h"\r
+#include "aoe.h"\r
+\r
+// in this file\r
+VOID STDCALL ProtocolOpenAdapterComplete(IN NDIS_HANDLE ProtocolBindingContext, IN NDIS_STATUS Status, IN NDIS_STATUS OpenErrorStatus);\r
+VOID STDCALL ProtocolCloseAdapterComplete(IN NDIS_HANDLE ProtocolBindingContext, IN NDIS_STATUS Status);\r
+VOID STDCALL ProtocolSendComplete(IN NDIS_HANDLE ProtocolBindingContext, IN PNDIS_PACKET Packet, IN NDIS_STATUS Status);\r
+VOID STDCALL ProtocolTransferDataComplete(IN NDIS_HANDLE ProtocolBindingContext, IN PNDIS_PACKET Packet, IN NDIS_STATUS Status, IN UINT BytesTransferred);\r
+VOID STDCALL ProtocolResetComplete(IN NDIS_HANDLE ProtocolBindingContext, IN NDIS_STATUS Status);\r
+VOID STDCALL ProtocolRequestComplete(IN NDIS_HANDLE ProtocolBindingContext, IN PNDIS_REQUEST NdisRequest, IN NDIS_STATUS Status);\r
+NDIS_STATUS STDCALL ProtocolReceive(IN NDIS_HANDLE ProtocolBindingContext, IN NDIS_HANDLE MacReceiveContext, IN PVOID HeaderBuffer, IN UINT HeaderBufferSize, IN PVOID LookAheadBuffer, IN UINT LookaheadBufferSize, IN UINT PacketSize);\r
+VOID STDCALL ProtocolReceiveComplete(IN NDIS_HANDLE ProtocolBindingContext);\r
+VOID STDCALL ProtocolStatus(IN NDIS_HANDLE ProtocolBindingContext, IN NDIS_STATUS GeneralStatus, IN PVOID StatusBuffer, IN UINT StatusBufferSize);\r
+VOID STDCALL ProtocolStatusComplete(IN NDIS_HANDLE  ProtocolBindingContext);\r
+VOID STDCALL ProtocolBindAdapter(OUT PNDIS_STATUS Status, IN NDIS_HANDLE BindContext, IN PNDIS_STRING DeviceName, IN PVOID SystemSpecific1, IN PVOID SystemSpecific2);\r
+VOID STDCALL ProtocolUnbindAdapter(OUT PNDIS_STATUS Status, IN NDIS_HANDLE ProtocolBindingContext, IN NDIS_HANDLE UnbindContext);\r
+NDIS_STATUS STDCALL ProtocolPnPEvent(IN NDIS_HANDLE  ProtocolBindingContext, IN PNET_PNP_EVENT NetPnPEvent);\r
+PCHAR STDCALL NetEventString(IN NET_PNP_EVENT_CODE NetEvent);\r
+\r
+#ifdef _MSC_VER\r
+#pragma pack(1)\r
+#endif\r
+typedef struct _HEADER {\r
+  UCHAR DestinationMac[6];\r
+  UCHAR SourceMac[6];\r
+  USHORT Protocol;\r
+  UCHAR Data[];\r
+} __attribute__((__packed__)) HEADER, *PHEADER;\r
+#ifdef _MSC_VER\r
+#pragma pack()\r
+#endif\r
+\r
+typedef struct _BINDINGCONTEXT {\r
+  BOOLEAN Active;\r
+  UCHAR Mac[6];\r
+  UINT MTU;\r
+  NDIS_STATUS Status;\r
+  NDIS_HANDLE PacketPoolHandle;\r
+  NDIS_HANDLE BufferPoolHandle;\r
+  NDIS_HANDLE BindingHandle;\r
+  KEVENT Event;\r
+  BOOLEAN OutstandingRequest;\r
+  PWCHAR AdapterName;\r
+  PWCHAR DeviceName;\r
+  struct _BINDINGCONTEXT *Next;\r
+} BINDINGCONTEXT, *PBINDINGCONTEXT;\r
+\r
+KEVENT ProtocolStopEvent;\r
+KSPIN_LOCK SpinLock;\r
+PBINDINGCONTEXT BindingContextList = NULL;\r
+NDIS_HANDLE ProtocolHandle = NULL;\r
+\r
+NTSTATUS STDCALL ProtocolStart() {\r
+  NDIS_STATUS Status;\r
+  NDIS_STRING ProtocolName;\r
+  NDIS_PROTOCOL_CHARACTERISTICS ProtocolCharacteristics;\r
+\r
+  DbgPrint("ProtocolStart\n");\r
+  KeInitializeEvent(&ProtocolStopEvent, SynchronizationEvent, FALSE);\r
+  KeInitializeSpinLock(&SpinLock);\r
+\r
+  RtlInitUnicodeString(&ProtocolName, L"AoE");\r
+  NdisZeroMemory(&ProtocolCharacteristics, sizeof(NDIS_PROTOCOL_CHARACTERISTICS));\r
+  ProtocolCharacteristics.MajorNdisVersion = 5;\r
+  ProtocolCharacteristics.MinorNdisVersion = 0;\r
+  ProtocolCharacteristics.Name = ProtocolName;\r
+  ProtocolCharacteristics.OpenAdapterCompleteHandler = ProtocolOpenAdapterComplete;\r
+  ProtocolCharacteristics.CloseAdapterCompleteHandler = ProtocolCloseAdapterComplete;\r
+  ProtocolCharacteristics.SendCompleteHandler = ProtocolSendComplete;\r
+  ProtocolCharacteristics.TransferDataCompleteHandler = ProtocolTransferDataComplete;\r
+  ProtocolCharacteristics.ResetCompleteHandler = ProtocolResetComplete;\r
+  ProtocolCharacteristics.RequestCompleteHandler = ProtocolRequestComplete;\r
+  ProtocolCharacteristics.ReceiveHandler = ProtocolReceive;\r
+  ProtocolCharacteristics.ReceiveCompleteHandler = ProtocolReceiveComplete;\r
+  ProtocolCharacteristics.StatusHandler = ProtocolStatus;\r
+  ProtocolCharacteristics.StatusCompleteHandler = ProtocolStatusComplete;\r
+  ProtocolCharacteristics.BindAdapterHandler = ProtocolBindAdapter;\r
+  ProtocolCharacteristics.UnbindAdapterHandler = ProtocolUnbindAdapter;\r
+  ProtocolCharacteristics.PnPEventHandler = ProtocolPnPEvent;\r
+  NdisRegisterProtocol((PNDIS_STATUS)&Status, &ProtocolHandle, &ProtocolCharacteristics, sizeof(NDIS_PROTOCOL_CHARACTERISTICS));\r
+  return Status;\r
+}\r
+\r
+VOID STDCALL ProtocolStop() {\r
+  NDIS_STATUS Status;\r
+\r
+  DbgPrint("ProtocolStop\n");\r
+  KeResetEvent(&ProtocolStopEvent);\r
+  NdisDeregisterProtocol(&Status, ProtocolHandle);\r
+  if (!NT_SUCCESS(Status)) Error("NdisDeregisterProtocol", Status);\r
+  if (BindingContextList != NULL) KeWaitForSingleObject(&ProtocolStopEvent, Executive, KernelMode, FALSE, NULL);\r
+}\r
+\r
+BOOLEAN STDCALL ProtocolSearchNIC(IN PUCHAR Mac) {\r
+  PBINDINGCONTEXT Context = BindingContextList;\r
+\r
+  while (Context != NULL) {\r
+    if (RtlCompareMemory(Mac, Context->Mac, 6) == 6) break;\r
+    Context = Context->Next;\r
+  }\r
+  if (Context != NULL) return TRUE;\r
+  return FALSE;\r
+}\r
+\r
+ULONG STDCALL ProtocolGetMTU(IN PUCHAR Mac) {\r
+  PBINDINGCONTEXT Context = BindingContextList;\r
+\r
+  while (Context != NULL) {\r
+    if (RtlCompareMemory(Mac, Context->Mac, 6) == 6) break;\r
+    Context = Context->Next;\r
+  }\r
+  if (Context == NULL) return 0;\r
+  return Context->MTU;\r
+}\r
+\r
+BOOLEAN STDCALL ProtocolSend(IN PUCHAR SourceMac, IN PUCHAR DestinationMac, IN PUCHAR Data, IN ULONG DataSize, IN PVOID PacketContext) {\r
+  PBINDINGCONTEXT Context = BindingContextList;\r
+  NDIS_STATUS Status;\r
+  PNDIS_PACKET Packet;\r
+  PNDIS_BUFFER Buffer;\r
+  PHEADER DataBuffer;\r
+#if defined(DEBUGALLPROTOCOLCALLS)\r
+  DbgPrint("ProtocolSend\n");\r
+#endif\r
+\r
+  if (RtlCompareMemory(SourceMac, "\xff\xff\xff\xff\xff\xff", 6) == 6) {\r
+    while (Context != NULL) {\r
+      ProtocolSend(Context->Mac, DestinationMac, Data, DataSize, NULL);\r
+      Context = Context->Next;\r
+    }\r
+    return TRUE;\r
+  }\r
+\r
+  while (Context != NULL) {\r
+    if (RtlCompareMemory(SourceMac, Context->Mac, 6) == 6) break;\r
+    Context = Context->Next;\r
+  }\r
+  if (Context == NULL) {\r
+    DbgPrint("ProtocolSend Can't find NIC %02x:%02x:%02x:%02x:%02x:%02x\n", SourceMac[0], SourceMac[1], SourceMac[2], SourceMac[3], SourceMac[4], SourceMac[5]);\r
+    return FALSE;\r
+  }\r
+\r
+  if (DataSize > Context->MTU) {\r
+    DbgPrint("ProtocolSend Tried to send oversized packet (size: %d, MTU:)\n", DataSize, Context->MTU);\r
+    return FALSE;\r
+  }\r
+\r
+  if ((DataBuffer = (PHEADER)ExAllocatePool(NonPagedPool, (sizeof(HEADER) + DataSize))) == NULL) {\r
+    DbgPrint("ProtocolSend ExAllocatePool\n");\r
+    return FALSE;\r
+  }\r
+\r
+  RtlCopyMemory(DataBuffer->SourceMac, SourceMac, 6);\r
+  RtlCopyMemory(DataBuffer->DestinationMac, DestinationMac, 6);\r
+  DataBuffer->Protocol = htons(AOEPROTOCOLID);\r
+  RtlCopyMemory(DataBuffer->Data, Data, DataSize);\r
+\r
+  NdisAllocatePacket(&Status, &Packet, Context->PacketPoolHandle);\r
+  if (!NT_SUCCESS(Status)) {\r
+    Error("ProtocolSend NdisAllocatePacket", Status);\r
+    ExFreePool(DataBuffer);\r
+    return FALSE;\r
+  }\r
+\r
+  NdisAllocateBuffer(&Status, &Buffer, Context->BufferPoolHandle, DataBuffer, (sizeof(HEADER) + DataSize));\r
+  if (!NT_SUCCESS(Status)) {\r
+    Error("ProtocolSend NdisAllocateBuffer", Status);\r
+    NdisFreePacket(Packet);\r
+    ExFreePool(DataBuffer);\r
+    return FALSE;\r
+  }\r
+\r
+  NdisChainBufferAtFront(Packet, Buffer);\r
+  *(PVOID*)Packet->ProtocolReserved = PacketContext;\r
+  NdisSend(&Status, Context->BindingHandle, Packet);\r
+  if (Status != NDIS_STATUS_PENDING) ProtocolSendComplete(Context, Packet, Status);\r
+  return TRUE;\r
+}\r
+\r
+VOID STDCALL ProtocolOpenAdapterComplete(IN NDIS_HANDLE ProtocolBindingContext, IN NDIS_STATUS Status, IN NDIS_STATUS OpenErrorStatus) {\r
+#if !defined(DEBUGMOSTPROTOCOLCALLS) && !defined(DEBUGALLPROTOCOLCALLS)\r
+  if (!NT_SUCCESS(Status))\r
+#endif\r
+  DbgPrint("ProtocolOpenAdapterComplete: 0x%08x 0x%08x\n", Status, OpenErrorStatus);\r
+}\r
+\r
+VOID STDCALL ProtocolCloseAdapterComplete(IN NDIS_HANDLE ProtocolBindingContext, IN NDIS_STATUS Status) {\r
+#if !defined(DEBUGMOSTPROTOCOLCALLS) && !defined(DEBUGALLPROTOCOLCALLS)\r
+  if (!NT_SUCCESS(Status))\r
+#endif\r
+  Error("ProtocolCloseAdapterComplete", Status);\r
+}\r
+\r
+VOID STDCALL ProtocolSendComplete(IN NDIS_HANDLE ProtocolBindingContext, IN PNDIS_PACKET Packet, IN NDIS_STATUS Status) {\r
+  PNDIS_BUFFER Buffer;\r
+  PUCHAR DataBuffer;\r
+#ifndef DEBUGALLPROTOCOLCALLS\r
+  if (!NT_SUCCESS(Status) && Status != NDIS_STATUS_NO_CABLE)\r
+#endif\r
+  Error("ProtocolSendComplete", Status);\r
+\r
+  NdisUnchainBufferAtFront(Packet, &Buffer);\r
+  if (Buffer != NULL) {\r
+    DataBuffer = NdisBufferVirtualAddress(Buffer);\r
+    ExFreePool(DataBuffer);\r
+    NdisFreeBuffer(Buffer);\r
+  } else {\r
+    DbgPrint("ProtocolSendComplete: Buffer == NULL\n");\r
+  }\r
+  NdisFreePacket(Packet);\r
+}\r
+\r
+VOID STDCALL ProtocolTransferDataComplete(IN NDIS_HANDLE ProtocolBindingContext, IN PNDIS_PACKET Packet, IN NDIS_STATUS Status, IN UINT BytesTransferred) {\r
+  PNDIS_BUFFER Buffer;\r
+  PHEADER Header = NULL;\r
+  PUCHAR Data = NULL;\r
+  UINT HeaderSize, DataSize;\r
+#ifndef DEBUGALLPROTOCOLCALLS\r
+  if (!NT_SUCCESS(Status))\r
+#endif\r
+  Error("ProtocolTransferDataComplete", Status);\r
+\r
+  NdisUnchainBufferAtFront(Packet, &Buffer);\r
+  if (Buffer != NULL) {\r
+    NdisQueryBuffer(Buffer, &Data, &DataSize);\r
+    NdisFreeBuffer(Buffer);\r
+  } else {\r
+    DbgPrint("ProtocolTransferDataComplete Data (front) Buffer == NULL\n");\r
+  }\r
+  NdisUnchainBufferAtBack(Packet, &Buffer);\r
+  if (Buffer != NULL) {\r
+    NdisQueryBuffer(Buffer, &Header, &HeaderSize);\r
+    NdisFreeBuffer(Buffer);\r
+  } else {\r
+    DbgPrint("ProtocolTransferDataComplete Header (back) Buffer == NULL\n");\r
+  }\r
+  if (Header != NULL && Data != NULL) AoEReply(Header->SourceMac, Header->DestinationMac, Data, DataSize);\r
+  if (Header != NULL) ExFreePool(Header);\r
+  if (Data != NULL) ExFreePool(Data);\r
+  NdisFreePacket(Packet);\r
+}\r
+\r
+VOID STDCALL ProtocolResetComplete(IN NDIS_HANDLE ProtocolBindingContext, IN NDIS_STATUS Status) {\r
+#if !defined(DEBUGMOSTPROTOCOLCALLS) && !defined(DEBUGALLPROTOCOLCALLS)\r
+  if (!NT_SUCCESS(Status))\r
+#endif\r
+  Error("ProtocolResetComplete", Status);\r
+}\r
+\r
+VOID STDCALL ProtocolRequestComplete(IN NDIS_HANDLE ProtocolBindingContext, IN PNDIS_REQUEST NdisRequest, IN NDIS_STATUS Status) {\r
+  PBINDINGCONTEXT Context = (PBINDINGCONTEXT)ProtocolBindingContext;\r
+#if !defined(DEBUGMOSTPROTOCOLCALLS) && !defined(DEBUGALLPROTOCOLCALLS)\r
+  if (!NT_SUCCESS(Status))\r
+#endif\r
+  Error("ProtocolRequestComplete", Status);\r
+\r
+  Context->Status = Status;\r
+  KeSetEvent(&Context->Event, 0, FALSE);\r
+}\r
+\r
+NDIS_STATUS STDCALL ProtocolReceive(IN NDIS_HANDLE ProtocolBindingContext, IN NDIS_HANDLE MacReceiveContext, IN PVOID HeaderBuffer, IN UINT HeaderBufferSize, IN PVOID LookAheadBuffer, IN UINT LookaheadBufferSize, IN UINT PacketSize) {\r
+  PBINDINGCONTEXT Context = (PBINDINGCONTEXT)ProtocolBindingContext;\r
+  NDIS_STATUS Status;\r
+  PNDIS_PACKET Packet;\r
+  PNDIS_BUFFER Buffer;\r
+  PHEADER Header;\r
+  PUCHAR HeaderCopy, Data;\r
+  UINT BytesTransferred;\r
+#ifdef DEBUGALLPROTOCOLCALLS\r
+  DbgPrint("ProtocolReceive\n");\r
+#endif\r
+\r
+  if (HeaderBufferSize != sizeof(HEADER)) {\r
+    DbgPrint("ProtocolReceive HeaderBufferSize %d != sizeof(HEADER) %d\n");\r
+    return NDIS_STATUS_NOT_ACCEPTED;\r
+  }\r
+  Header = (PHEADER)HeaderBuffer;\r
+  if (ntohs(Header->Protocol) != AOEPROTOCOLID) return NDIS_STATUS_NOT_ACCEPTED;\r
+\r
+  if (LookaheadBufferSize == PacketSize) {\r
+    AoEReply(Header->SourceMac, Header->DestinationMac, LookAheadBuffer, PacketSize);\r
+    return NDIS_STATUS_SUCCESS;\r
+  }\r
+\r
+  if ((HeaderCopy = (PUCHAR)ExAllocatePool(NonPagedPool, HeaderBufferSize)) == NULL) {\r
+    DbgPrint("ProtocolReceive ExAllocatePool HeaderCopy\n");\r
+    return NDIS_STATUS_NOT_ACCEPTED;\r
+  }\r
+  RtlCopyMemory(HeaderCopy, HeaderBuffer, HeaderBufferSize);\r
+  if ((Data = (PUCHAR)ExAllocatePool(NonPagedPool, PacketSize)) == NULL) {\r
+    DbgPrint("ProtocolReceive ExAllocatePool HeaderData\n");\r
+    ExFreePool(HeaderCopy);\r
+    return NDIS_STATUS_NOT_ACCEPTED;\r
+  }\r
+  NdisAllocatePacket(&Status, &Packet, Context->PacketPoolHandle);\r
+  if (!NT_SUCCESS(Status)) {\r
+    Error("ProtocolReceive NdisAllocatePacket", Status);\r
+    ExFreePool(Data);\r
+    ExFreePool(HeaderCopy);\r
+    return NDIS_STATUS_NOT_ACCEPTED;\r
+  }\r
+\r
+  NdisAllocateBuffer(&Status, &Buffer, Context->BufferPoolHandle, Data, PacketSize);\r
+  if (!NT_SUCCESS(Status)) {\r
+    Error("ProtocolReceive NdisAllocateBuffer (Data)", Status);\r
+    NdisFreePacket(Packet);\r
+    ExFreePool(Data);\r
+    ExFreePool(HeaderCopy);\r
+    return NDIS_STATUS_NOT_ACCEPTED;\r
+  }\r
+  NdisChainBufferAtFront(Packet, Buffer);\r
+\r
+  NdisAllocateBuffer(&Status, &Buffer, Context->BufferPoolHandle, HeaderCopy, PacketSize);\r
+  if (!NT_SUCCESS(Status)) {\r
+    Error("ProtocolReceive NdisAllocateBuffer (HeaderCopy)", Status);\r
+    NdisUnchainBufferAtFront(Packet, &Buffer);\r
+    NdisFreeBuffer(Buffer);\r
+    NdisFreePacket(Packet);\r
+    ExFreePool(Data);\r
+    ExFreePool(HeaderCopy);\r
+    return NDIS_STATUS_NOT_ACCEPTED;\r
+  }\r
+  NdisChainBufferAtBack(Packet, Buffer);\r
+\r
+  NdisTransferData(&Status, Context->BindingHandle, MacReceiveContext, 0, PacketSize, Packet, &BytesTransferred);\r
+  if (Status != NDIS_STATUS_PENDING) ProtocolTransferDataComplete(ProtocolBindingContext, Packet, Status, BytesTransferred);\r
+  return Status;\r
+}\r
+\r
+VOID STDCALL ProtocolReceiveComplete(IN NDIS_HANDLE ProtocolBindingContext) {\r
+#ifdef DEBUGALLPROTOCOLCALLS\r
+  DbgPrint("ProtocolReceiveComplete\n");\r
+#endif\r
+}\r
+\r
+VOID STDCALL ProtocolStatus(IN NDIS_HANDLE ProtocolBindingContext, IN NDIS_STATUS GeneralStatus, IN PVOID StatusBuffer, IN UINT StatusBufferSize) {\r
+#if !defined(DEBUGMOSTPROTOCOLCALLS) && !defined(DEBUGALLPROTOCOLCALLS)\r
+  if (!NT_SUCCESS(GeneralStatus))\r
+#endif\r
+  Error("ProtocolStatus", GeneralStatus);\r
+}\r
+\r
+VOID STDCALL ProtocolStatusComplete(IN NDIS_HANDLE  ProtocolBindingContext) {\r
+#if defined(DEBUGMOSTPROTOCOLCALLS) || defined(DEBUGALLPROTOCOLCALLS)\r
+  DbgPrint("ProtocolStatusComplete\n");\r
+#endif\r
+}\r
+\r
+VOID STDCALL ProtocolBindAdapter(OUT PNDIS_STATUS StatusOut, IN NDIS_HANDLE BindContext, IN PNDIS_STRING DeviceName, IN PVOID SystemSpecific1, IN PVOID SystemSpecific2) {\r
+  PBINDINGCONTEXT Context, Walker;\r
+  NDIS_STATUS Status;\r
+  NDIS_STATUS OpenErrorStatus;\r
+  UINT SelectedMediumIndex, MTU;\r
+  NDIS_MEDIUM MediumArray[] = {NdisMedium802_3};\r
+  NDIS_STRING AdapterInstanceName;\r
+  NDIS_REQUEST Request;\r
+  ULONG InformationBuffer = NDIS_PACKET_TYPE_DIRECTED;\r
+  UCHAR Mac[6];\r
+  KIRQL Irql;\r
+#if defined(DEBUGMOSTPROTOCOLCALLS) || defined(DEBUGALLPROTOCOLCALLS)\r
+  DbgPrint("ProtocolBindAdapter\n");\r
+#endif\r
+\r
+  if ((Context = (NDIS_HANDLE)ExAllocatePool(NonPagedPool, sizeof(BINDINGCONTEXT))) == NULL) {\r
+    DbgPrint("ProtocolBindAdapter ExAllocatePool\n");\r
+    *StatusOut = NDIS_STATUS_RESOURCES;\r
+    return;\r
+  }\r
+  Context->Next = NULL;\r
+  KeInitializeEvent(&Context->Event, SynchronizationEvent, FALSE);\r
+\r
+  NdisAllocatePacketPool(&Status, &Context->PacketPoolHandle, POOLSIZE, (4 * sizeof(VOID*)));\r
+  if (!NT_SUCCESS(Status)) {\r
+    Error("ProtocolBindAdapter NdisAllocatePacketPool", Status);\r
+    ExFreePool(Context);\r
+    *StatusOut = NDIS_STATUS_RESOURCES;\r
+    return;\r
+  }\r
+\r
+  NdisAllocateBufferPool(&Status, &Context->BufferPoolHandle, POOLSIZE);\r
+  if (!NT_SUCCESS(Status)) {\r
+    Error("ProtocolBindAdapter NdisAllocateBufferPool", Status);\r
+    NdisFreePacketPool(Context->PacketPoolHandle);\r
+    ExFreePool(Context);\r
+    *StatusOut = NDIS_STATUS_RESOURCES;\r
+    return;\r
+  }\r
+\r
+  NdisOpenAdapter(&Status, &OpenErrorStatus, &Context->BindingHandle, &SelectedMediumIndex, MediumArray, (sizeof(MediumArray) / sizeof(NDIS_MEDIUM)), ProtocolHandle, Context, DeviceName, 0, NULL);\r
+  if (!NT_SUCCESS(Status)) {\r
+    DbgPrint("ProtocolBindAdapter NdisOpenAdapter 0x%lx 0x%lx\n", Status, OpenErrorStatus);\r
+    NdisFreePacketPool(Context->PacketPoolHandle);\r
+    NdisFreeBufferPool(Context->BufferPoolHandle);\r
+    ExFreePool(Context->AdapterName);\r
+    ExFreePool(Context->DeviceName);\r
+    ExFreePool(Context);\r
+    *StatusOut = Status;\r
+    return;\r
+  }\r
+  if (SelectedMediumIndex != 0) DbgPrint("ProtocolBindAdapter NdisOpenAdapter SelectedMediumIndex: %d\n", SelectedMediumIndex);\r
+\r
+  Context->AdapterName = NULL;\r
+  if (NT_SUCCESS(Status = NdisQueryAdapterInstanceName(&AdapterInstanceName, Context->BindingHandle))) {\r
+    if ((Context->AdapterName = (PWCHAR)ExAllocatePool(NonPagedPool, AdapterInstanceName.Length + sizeof(WCHAR))) == NULL) {\r
+      DbgPrint("ProtocolBindAdapter ExAllocatePool AdapterName\n");\r
+    } else {\r
+      RtlZeroMemory(Context->AdapterName, AdapterInstanceName.Length + sizeof(WCHAR));\r
+      RtlCopyMemory(Context->AdapterName, AdapterInstanceName.Buffer, AdapterInstanceName.Length);\r
+    }\r
+    NdisFreeMemory(AdapterInstanceName.Buffer, 0, 0);\r
+  } else {\r
+    Error("ProtocolBindAdapter NdisQueryAdapterInstanceName", Status);\r
+  }\r
+\r
+  Context->DeviceName = NULL;\r
+  if (DeviceName->Length > 0) {\r
+    if ((Context->DeviceName = (PWCHAR)ExAllocatePool(NonPagedPool, DeviceName->Length + sizeof(WCHAR))) == NULL) {\r
+      DbgPrint("ProtocolBindAdapter ExAllocatePool DeviceName\n");\r
+    } else {\r
+      RtlZeroMemory(Context->DeviceName, DeviceName->Length + sizeof(WCHAR));\r
+      RtlCopyMemory(Context->DeviceName, DeviceName->Buffer, DeviceName->Length);\r
+    }\r
+  }\r
+\r
+  if (Context->AdapterName != NULL) DbgPrint("Adapter: %S\n", Context->AdapterName);\r
+  if (Context->DeviceName != NULL) DbgPrint("Device Name: %S\n", Context->DeviceName);\r
+  if ((Context->AdapterName == NULL) && (Context->DeviceName == NULL)) DbgPrint("Unnamed Adapter...\n");\r
+\r
+  Request.RequestType = NdisRequestQueryInformation;\r
+  Request.DATA.QUERY_INFORMATION.Oid = OID_802_3_CURRENT_ADDRESS;\r
+  Request.DATA.QUERY_INFORMATION.InformationBuffer = Mac;\r
+  Request.DATA.QUERY_INFORMATION.InformationBufferLength = sizeof(Mac);\r
+\r
+  KeResetEvent(&Context->Event);\r
+  NdisRequest(&Status, Context->BindingHandle, &Request);\r
+  if (Status == NDIS_STATUS_PENDING) {\r
+    KeWaitForSingleObject(&Context->Event, Executive, KernelMode, FALSE, NULL);\r
+    Status = Context->Status;\r
+  }\r
+  if (!NT_SUCCESS(Status)) {\r
+    Error("ProtocolBindAdapter NdisRequest (Mac)", Status);\r
+  } else {\r
+    RtlCopyMemory(Context->Mac, Mac, 6);\r
+    DbgPrint("Mac: %02x:%02x:%02x:%02x:%02x:%02x\n", Mac[0], Mac[1], Mac[2], Mac[3], Mac[4], Mac[5]);\r
+  }\r
+\r
+  Request.RequestType = NdisRequestQueryInformation;\r
+  Request.DATA.QUERY_INFORMATION.Oid = OID_GEN_MAXIMUM_FRAME_SIZE;\r
+  Request.DATA.QUERY_INFORMATION.InformationBuffer = &MTU;\r
+  Request.DATA.QUERY_INFORMATION.InformationBufferLength = sizeof(MTU);\r
+\r
+  KeResetEvent(&Context->Event);\r
+  NdisRequest(&Status, Context->BindingHandle, &Request);\r
+  if (Status == NDIS_STATUS_PENDING) {\r
+    KeWaitForSingleObject(&Context->Event, Executive, KernelMode, FALSE, NULL);\r
+    Status = Context->Status;\r
+  }\r
+  if (!NT_SUCCESS(Status)) {\r
+    Error("ProtocolBindAdapter NdisRequest (MTU)", Status);\r
+  } else {\r
+    Context->MTU = MTU;\r
+    DbgPrint("MTU: %d\n", MTU);\r
+  }\r
+\r
+  Request.RequestType = NdisRequestSetInformation;\r
+  Request.DATA.SET_INFORMATION.Oid = OID_GEN_CURRENT_PACKET_FILTER;\r
+  Request.DATA.SET_INFORMATION.InformationBuffer = &InformationBuffer;\r
+  Request.DATA.SET_INFORMATION.InformationBufferLength = sizeof(InformationBuffer);\r
+\r
+  KeResetEvent(&Context->Event);\r
+  NdisRequest(&Status, Context->BindingHandle, &Request);\r
+  if (Status == NDIS_STATUS_PENDING) {\r
+    KeWaitForSingleObject(&Context->Event, Executive, KernelMode, FALSE, NULL);\r
+    Status = Context->Status;\r
+  }\r
+  if (!NT_SUCCESS(Status)) Error("ProtocolBindAdapter NdisRequest (filter)", Status);\r
+\r
+  KeAcquireSpinLock(&SpinLock, &Irql);\r
+  if (BindingContextList == NULL) {\r
+    BindingContextList = Context;\r
+  } else {\r
+    for (Walker = BindingContextList; Walker->Next != NULL; Walker = Walker->Next);\r
+    Walker->Next = Context;\r
+  }\r
+  KeReleaseSpinLock(&SpinLock, Irql);\r
+\r
+  AoEResetProbe();\r
+  *StatusOut = NDIS_STATUS_SUCCESS;\r
+}\r
+\r
+VOID STDCALL ProtocolUnbindAdapter(OUT PNDIS_STATUS StatusOut, IN NDIS_HANDLE ProtocolBindingContext, IN NDIS_HANDLE UnbindContext) {\r
+  PBINDINGCONTEXT Context = (PBINDINGCONTEXT)ProtocolBindingContext;\r
+  PBINDINGCONTEXT Walker, PreviousContext;\r
+  NDIS_STATUS Status;\r
+  KIRQL Irql;\r
+#if defined(DEBUGMOSTPROTOCOLCALLS) || defined(DEBUGALLPROTOCOLCALLS)\r
+  DbgPrint("ProtocolUnbindAdapter\n");\r
+#endif\r
+\r
+  PreviousContext = NULL;\r
+  KeAcquireSpinLock(&SpinLock, &Irql);\r
+  for (Walker = BindingContextList; Walker != Context && Walker != NULL; Walker = Walker->Next) PreviousContext = Walker;\r
+  if (Walker == NULL) {\r
+    DbgPrint("Context not found in BindingContextList!!\n");\r
+    KeReleaseSpinLock(&SpinLock, Irql);\r
+    return;\r
+  }\r
+  if (PreviousContext == NULL) {\r
+    BindingContextList = Walker->Next;\r
+  } else {\r
+    PreviousContext->Next = Walker->Next;\r
+  }\r
+  KeReleaseSpinLock(&SpinLock, Irql);\r
+\r
+  NdisCloseAdapter(&Status, Context->BindingHandle);\r
+  if (!NT_SUCCESS(Status)) Error("ProtocolUnbindAdapter NdisCloseAdapter", Status);\r
+  NdisFreePacketPool(Context->PacketPoolHandle);\r
+  NdisFreeBufferPool(Context->BufferPoolHandle);\r
+  ExFreePool(Context);\r
+  if (BindingContextList == NULL) KeSetEvent(&ProtocolStopEvent, 0, FALSE);\r
+  *StatusOut = NDIS_STATUS_SUCCESS;\r
+}\r
+\r
+NDIS_STATUS STDCALL ProtocolPnPEvent(IN NDIS_HANDLE ProtocolBindingContext, IN PNET_PNP_EVENT NetPnPEvent) {\r
+#if defined(DEBUGMOSTPROTOCOLCALLS) || defined(DEBUGALLPROTOCOLCALLS)\r
+  DbgPrint("ProtocolPnPEvent %s\n", NetEventString(NetPnPEvent->NetEvent));\r
+#endif\r
+  if (ProtocolBindingContext == NULL && NetPnPEvent->NetEvent == NetEventReconfigure) {\r
+#ifdef _MSC_VER\r
+    NdisReEnumerateProtocolBindings(ProtocolHandle);\r
+#else\r
+    DbgPrint("No vector to NdisReEnumerateProtocolBindings\n");\r
+#endif\r
+  }\r
+  if (NetPnPEvent->NetEvent == NetEventQueryRemoveDevice) {\r
+    return NDIS_STATUS_FAILURE;\r
+  } else {\r
+    return NDIS_STATUS_SUCCESS;\r
+  }\r
+}\r
+\r
+PCHAR STDCALL NetEventString(IN NET_PNP_EVENT_CODE NetEvent) {\r
+  switch (NetEvent) {\r
+    case NetEventSetPower:           return "NetEventSetPower";\r
+    case NetEventQueryPower:         return "NetEventQueryPower";\r
+    case NetEventQueryRemoveDevice:  return "NetEventQueryRemoveDevice";\r
+    case NetEventCancelRemoveDevice: return "NetEventCancelRemoveDevice";\r
+    case NetEventReconfigure:        return "NetEventReconfigure";\r
+    case NetEventBindList:           return "NetEventBindList";\r
+    case NetEventBindsComplete:      return "NetEventBindsComplete";\r
+    case NetEventPnPCapabilities:    return "NetEventPnPCapabilities";\r
+    default:                         return "NetEventUnknown";\r
+  }\r
+}\r
diff --git a/src/protocol.h b/src/protocol.h
new file mode 100644 (file)
index 0000000..2efb4aa
--- /dev/null
@@ -0,0 +1,29 @@
+/*\r
+  Copyright 2006-2008, V.\r
+  For contact information, see http://winaoe.org/\r
+\r
+  This file is part of WinAoE.\r
+\r
+  WinAoE is free software: you can redistribute it and/or modify\r
+  it under the terms of the GNU General Public License as published by\r
+  the Free Software Foundation, either version 3 of the License, or\r
+  (at your option) any later version.\r
+\r
+  WinAoE is distributed in the hope that it will be useful,\r
+  but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+  GNU General Public License for more details.\r
+\r
+  You should have received a copy of the GNU General Public License\r
+  along with WinAoE.  If not, see <http://www.gnu.org/licenses/>.\r
+*/\r
+\r
+#ifndef _PROTOCOL_H\r
+#define _PROTOCOL_H\r
+#include "portable.h"\r
+\r
+BOOLEAN STDCALL ProtocolSearchNIC(IN PUCHAR Mac);\r
+ULONG STDCALL ProtocolGetMTU(IN PUCHAR Mac);\r
+BOOLEAN STDCALL ProtocolSend(IN PUCHAR SourceMac, IN PUCHAR DestinationMac, IN PUCHAR Data, IN ULONG DataSize, IN PVOID PacketContext);\r
+\r
+#endif\r
diff --git a/src/pxe.asm/Makefile b/src/pxe.asm/Makefile
new file mode 100644 (file)
index 0000000..293955d
--- /dev/null
@@ -0,0 +1,41 @@
+all: aoe.0
+
+clean:
+       rm -rf obj
+
+obj/aoe.o: aoe.S aoe.h Makefile
+       @rm -rf aoe.0
+       @mkdir -p obj
+       gcc -Wall -c -o obj/aoe.o aoe.S
+
+obj/pxe.o: pxe.S aoe.h Makefile
+       @rm -rf aoe.0
+       @mkdir -p obj
+       gcc -Wall -c -o obj/pxe.o pxe.S
+
+obj/int13.o: int13.S aoe.h Makefile
+       @rm -rf aoe.0
+       @mkdir -p obj
+       gcc -Wall -c -o obj/int13.o int13.S
+
+obj/lib.o: lib.S aoe.h Makefile
+       @rm -rf aoe.0
+       @mkdir -p obj
+       gcc -Wall -c -o obj/lib.o lib.S
+
+obj/global.o: global.S aoe.h Makefile
+       @rm -rf aoe.0
+       @mkdir -p obj
+       gcc -Wall -c -o obj/global.o global.S
+
+obj/debug.o: debug.S aoe.h Makefile
+       @rm -rf aoe.0
+       @mkdir -p obj
+       gcc -Wall -c -o obj/debug.o debug.S
+
+aoe.0: aoe.ld obj/aoe.o obj/pxe.o obj/int13.o obj/lib.o obj/global.o obj/debug.o Makefile
+       @rm -rf aoe.0
+       ld -static -T aoe.ld obj/aoe.o obj/pxe.o obj/int13.o obj/lib.o obj/global.o obj/debug.o -o obj/aoe
+       objcopy -O binary obj/aoe aoe.0
+       @if [ `expr \`find aoe.0 -printf "%s"\` % 2` == 0 ]; then echo -en "\0" >> aoe.0; fi
+       @find aoe.0 -printf "%f size: %s\n"
diff --git a/src/pxe.asm/aoe.S b/src/pxe.asm/aoe.S
new file mode 100644 (file)
index 0000000..2534bf8
--- /dev/null
@@ -0,0 +1,285 @@
+/*
+  Copyright 2006-2008, V.
+  For contact information, see http://winaoe.org/
+
+  This file is part of WinAoE.
+
+  WinAoE is free software: you can 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.
+
+  WinAoE is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with WinAoE.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "aoe.h"
+
+start:
+       pushfl                          # save eflags
+       pushw   %ax                     # save ax
+       call    0f                      # pushl ip
+0:     popw    %ax                     # popl ip
+       subw    $0b, %ax                # offset by 0: to get _start adress
+       cmpw    $0x7c00, %ax            # did we start from 0x7c00?
+       je      0f                      # if not, print error
+       popw    %ax                     # restore ax (cosmetic)
+       popfl                           # restore flags (cosmetic)
+       print   "\nip is not 0x7c00, can not continue...\n"
+       halt
+0:     movw    %cs, %ax                # get %cs
+       cmpw    $0x0000, %ax            # is %cs 0x0000?
+       je      0f                      # if not, print error
+       popw    %ax                     # restore ax (cosmetic)
+       popfl                           # restore flags (cosmetic)
+       print   "\ncs is not 0x0000, can not continue...\n"
+       halt
+0:     popw    %ax                     # restore ax
+       popfl                           # restore eflags
+       ljmp    $0x07c0, $0f            # realign cs:eip to let start be 0
+
+0:     movw    $0, %bp                 # use bp to set ss
+       movw    %bp, %ss                # setup new stack
+       movw    $0x7c00, %sp            # setup sp to below boot sector
+       movw    $0x7c00, %bp            # setup bp to the same
+
+       pushfl                          # everything should have its initial
+       pushal                          # values, so push it all on the stack
+       pushw   %ds
+       pushw   %es
+       pushw   %fs
+       pushw   %gs
+
+       int     $0x12                   # get memory size in kb in ax
+       shlw    $6, %ax                 # change from kb to paragraphs
+       movw    $_pxesize, %bx          # get pxe size
+       addw    $0x0f, %bx              # add 15 to round up on paragraph
+       shrw    $4, %bx                 # change to paragraphs
+       subw    %bx, %ax                # calculate target segment
+       andw    $0xffc0, %ax            # round down to kb boundry
+       movw    %ax, %es                # set es as target segment
+       shrw    $6, %ax                 # convert to kb for new free mem
+       pushw   $0x0040                 # bios area
+       popw    %ds
+       movw    %ax, %ds:0x0013         # store in bios area at 0040:0013
+       pushw   %cs                     # read from segment 07c0
+       popw    %ds
+       xorw    %si, %si                # zero si
+       xorw    %di, %di                # zero di
+       movw    $_pxesize, %cx          # get size
+       cld                             # positive direction
+       rep     movsb                   # copy ourself to target segment
+       pushw   %es                     # setup segment for lret
+       pushw   $0f                     # setup offset for lret
+       lret                            # long return into target segment
+
+0:     print   "\nWelcome to AoE Boot...\n\n"
+
+#ifdef DEBUG
+       call    debuginit               # init debug vectors (debug.S)
+       pushw   $0x0000                 # set es ready for access to the bios
+       popw    %es                     # area and loading the boot sector
+       movw    $0x7c00, %di
+       movw    $(0xffff - 0x7c00), %cx
+       movb    $0xcc, %al              # int3 (break)
+       cld
+       rep     stosb                   # fill 0000:7c00-0000:ffff with breaks
+#endif
+
+       call    pxeinit                 # init pxe api and get rootpath (pxe.S)
+//movb $0, %cs:_irq            # always use polling
+       call    printaoeparameters      # print aoe parameters
+       call    getdiskparameters       # get disk config (pxe.S)
+       call    printdiskparameters     # print disk parameters
+       call    int13init               # setup int13 handler (int13.S)
+
+       pushw   $0x0000                 # set es ready for access to the bios
+       popw    %es                     # area and loading the boot sector
+1:     print   "\nBoot from (N)etwork, (H)arddisk or (F)loppy?\n"
+       pushw   $TIMEOUT
+       call    getkey
+       cmpb    $0, %al
+       je      1f                      # default to network boot
+       cmpb    $'Z', %al               # make input upcase
+       jna     0f
+       subb    $('a' - 'A'), %al
+0:     cmpb    $'N', %al
+       je      1f
+       cmpb    $'H', %al
+       je      2f
+       cmpb    $'F', %al
+       je      3f
+       jmp     1b                      # input error
+
+1:     movb    $0x80, %cs:_drive       # aoe drive is 1st harddisk
+       movw    $aBFT, %bx              # calculate aBFT segment boundry
+       subw    %bx, 1                  # (x-1) & 0xfff0 + 0x10
+       andw    $0xfff0, %bx
+       addw    $0x10, %bx
+
+       movl    $0x54464261, %cs:(%bx)  # setup aBFT
+       movl    $(slack - aBFT), %cs:(length - aBFT)(%bx)
+       movb    $1, %cs:(revision - aBFT)(%bx)
+       movl    %cs:_clientmac, %eax    # client mac (high 4)
+       movl    %eax, %cs:(clientmac - aBFT)(%bx)
+       movw    %cs:_clientmac + 4, %ax # client mac (low 2)
+       movw    %ax, %cs:(clientmac - aBFT + 4)(%bx)
+       movw    %cs:_major, %ax         # major
+       movw    %ax, %cs:(major - aBFT)(%bx)
+       movb    %cs:_minor, %al         # minor
+       movb    %al, %cs:(minor - aBFT)(%bx)
+
+       movw    $(slack - aBFT), %cx    # length
+       pushw   %bx                     # keep safe
+       xorb    %al, %al                # zero checksum
+0:     subb    %cs:(%bx), %al
+       incw    %bx                     # by counting through %bx
+       decw    %cx                     # %cx times...
+       jnz     0b
+       popw    %bx                     # get aBFT address and store checksum
+       movb    %al, %cs:(checksum - aBFT)(%bx)
+
+       movb    $1, %es:0x0475          # 1 harddisk
+       movb    $0x80, %dl              # boot from harddisk
+       jmp     0f
+2:     movb    $0x81, %cs:_drive       # aoe drive is 2nd harddisk
+       movb    $2, %es:0x0475          # 2 harddisks
+       movb    $0x80, %dl              # boot from harddisk
+       jmp     0f
+3:     movb    $0x80, %cs:_drive       # aoe drive is 1st harddisk
+       movb    $1, %es:0x0475          # 1 harddisk
+       movb    $0x00, %dl              # boot from floppy
+
+0:     movb    $0x02, %ah              # load sector 0 in 0:7c00
+       movb    $1, %al
+       movb    $0, %ch
+       movb    $1, %cl
+       movb    $0, %dh
+       pushw   $0x0000
+       popw    %es
+       movw    $0x7c00, %bx
+       int     $0x13
+       jnc     0f
+       print   "Hardware boot failure\n"
+       halt
+
+0:     popw    %gs                     # pop everything to revert
+       popw    %fs                     # to starting state
+       popw    %es
+       popw    %ds
+       popal
+       popfl
+
+       movb    $0x80, %dl              # for ReactOS freeloader
+       ljmp    $0x0000, $0x7c00        # long jump to bootsector
+
+
+# printaoeparameters: print rootpath AoE setting
+printaoeparameters:
+       enter   $0, $0
+       pushw   %bx
+
+       print   "Boot from: e"
+       pushw   %cs:_major
+       call    printnumber
+       print   "."
+       pushw   %cs:_minor
+       call    printnumber
+
+       xorw    %bx, %bx
+       print   "  Client Address: "
+0:     pushw   %cs:_clientmac(%bx)
+       call    printbyte
+       pushw   $':'
+       call    printchar
+       incw    %bx
+       cmpw    $5, %bx
+       jb      0b
+       pushw   %cs:_clientmac(%bx)
+       call    printbyte
+
+       print   "  Irq: "
+       pushw   %cs:_irq
+       call    printnumber
+       cmpb    $0, %cs:_irq
+       jne     0f
+       print   " (polling)"
+
+0:     call    line
+       popw    %bx
+       leave
+       ret     $0
+
+# printdiskparameters: prints disk parameters
+printdiskparameters:
+       enter   $0, $0
+       pushl   %eax
+       pushw   %bx
+
+       xorw    %bx, %bx
+       print   "Server Address: "
+0:     pushw   %cs:_servermac(%bx)
+       call    printbyte
+       pushw   $':'
+       call    printchar
+       incw    %bx
+       cmpw    $5, %bx
+       jb      0b
+       pushw   %cs:_servermac(%bx)
+       call    printbyte
+       call    line
+
+       movl    %cs:_size, %eax
+       shrl    $11, %eax
+       print   "Disk Size: "
+       pushl   %eax
+       call    printlongnumber
+       print   "M Cylinders: "
+       pushl   %cs:_cylinders
+       call    printlongnumber
+       print   " Heads: "
+       xorb    %ah, %ah
+       movb    %cs:_heads, %al
+       pushw   %ax
+       call    printnumber
+       print   " Sectors: "
+       movb    %cs:_sectors, %al
+       pushw   %ax
+       call    printnumber
+       call    line
+
+       popw    %bx
+       popl    %eax
+       leave
+       ret     $0
+
+aBFT:
+signature:
+       .org    .+4, 0
+length:
+       .org    .+4, 0
+revision:
+       .org    .+1, 0
+checksum:
+       .org    .+1, 0
+oemid:
+       .org    .+6, 0
+oemtableid:
+       .org    .+8, 0
+reserved1:
+       .org    .+12, 0
+major:
+       .org    .+2, 0
+minor:
+       .org    .+1, 0
+reserved2:
+       .org    .+1, 0
+clientmac:
+       .org    .+6, 0
+slack:
+       .org    .+15, 0
diff --git a/src/pxe.asm/aoe.h b/src/pxe.asm/aoe.h
new file mode 100644 (file)
index 0000000..ff26a55
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+  Copyright 2006-2008, V.
+  For contact information, see http://winaoe.org/
+
+  This file is part of WinAoE.
+
+  WinAoE is free software: you can 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.
+
+  WinAoE is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with WinAoE.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+.code16
+//#define DEBUG
+//#define CHKSUM
+#define SERIAL
+
+#define BREAK 0
+#define TIMEOUT 55
+
+#define print call printline; .asciz
+#define halt jmp haltcpu
+#define D call debug;
+#define N call ndebug;
+
+#define AoEdstaddr     0
+#define AoEsrcaddr     6
+#define AoEprotocol    12
+#define AoEver         14
+#define AoEflags       14
+#define AoEerror       15
+#define AoEmajor       16
+#define AoEminor       18
+#define AoEcommand     19
+#define AoEtag         20
+#define AoEaflags      24
+#define AoEerr         25
+#define AoEfeature     25
+#define AoEcount       26
+#define AoEcmd         27
+#define AoEstatus      27
+#define AoElba0                28
+#define AoElba1                29
+#define AoElba2                30
+#define AoElba3                31
+#define AoElba4                32
+#define AoElba5                33
+#define AoEreserved    34
+#define AoEdata                36
+#define AoEsize                1518
diff --git a/src/pxe.asm/aoe.ld b/src/pxe.asm/aoe.ld
new file mode 100644 (file)
index 0000000..5bae6f2
--- /dev/null
@@ -0,0 +1,25 @@
+/*
+  Copyright 2006-2008, V.
+  For contact information, see http://winaoe.org/
+
+  This file is part of WinAoE.
+
+  WinAoE is free software: you can 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.
+
+  WinAoE is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with WinAoE.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+SECTIONS {
+  . = 0;
+  .text : {*(*)}
+}
+PROVIDE(_pxesize = .);
diff --git a/src/pxe.asm/debug.S b/src/pxe.asm/debug.S
new file mode 100644 (file)
index 0000000..ac6ca7e
--- /dev/null
@@ -0,0 +1,361 @@
+/*
+  Copyright 2006-2008, V.
+  For contact information, see http://winaoe.org/
+
+  This file is part of WinAoE.
+
+  WinAoE is free software: you can 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.
+
+  WinAoE is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with WinAoE.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "aoe.h"
+
+.globl _debug_srcaddr, _debug_undi_transmit_packet, _debug_undi_TBD
+
+_debug:
+_debug_dstaddr:                .org    .+6, 0xff
+_debug_srcaddr:                .org    .+6, 0
+_debug_protocol:       .word   0x0180
+_debug_count:          .long   0
+_debug_eflags:         .long   0
+_debug_ip:             .word   0
+_debug_cs:             .word   0
+_debug_ds:             .word   0
+_debug_es:             .word   0
+_debug_fs:             .word   0
+_debug_gs:             .word   0
+_debug_ss:             .word   0
+_debug_ebp:            .long   0
+_debug_esp:            .long   0
+_debug_eax:            .long   0
+_debug_ebx:            .long   0
+_debug_ecx:            .long   0
+_debug_edx:            .long   0
+_debug_esi:            .long   0
+_debug_edi:            .long   0
+_debug_end:
+
+_debug_undi_transmit_packet:           # 0x0008
+       .word   0                       # PXENV_STATUS Status
+       .byte   0                       # UINT8 Protocol
+       .byte   1                       # UINT8 XmitFlag
+       .long   _debug_dstaddr          # SEGOFF16 DestAddr
+       .long   _debug_undi_TBD         # SEGOFF16 TBD
+       .org    .+(2 * 4), 0            # UINT32 Reserved[2]
+
+_debug_undi_TBD:
+       .word   (_debug_end - _debug)   # UINT16 ImmedLength
+       .long   _debug                  # SEGOFF16 Xmit
+       .word   0                       # UINT16 DataBlkCount
+       .org    .+(8 * 8), 0            # DataBlk DataBlock[8]
+
+_count:        .long   0
+
+# sets exception vectors
+.globl debuginit
+debuginit:
+       enter   $0, $0
+       pushf
+       push    %es
+       push    $0
+       pop     %es
+       pushw   %cs
+       popw    %es:((0x3 * 4) + 2)
+       pushw   $int3
+       popw    %es:(0x3 * 4)
+       pop     %es
+       popf
+       leave
+       ret     $0
+
+# int3: break (prints cpu state and halts)
+int3:
+       call    debug
+       jmp     .
+
+# count: inceases _count, break when BREAK reached
+.globl count
+count:
+       enter   $0, $0
+       pushf
+       push    %eax
+       incl    %cs:_count
+       mov     $BREAK, %eax
+       cmpl    $0, %eax
+       pop     %eax
+       je      0f
+       cmpl    $BREAK, %cs:_count
+       jb      0f
+       print   "Break on: "
+       push    $BREAK
+       call    printword
+       call    line
+       popf
+       call    debug
+       halt
+0:     popf
+       leave
+       ret     $0
+
+# debug: prints cpu state
+.globl debug
+debug:
+       enter   $0, $0
+       pushfl
+       pushal
+       print   "count:"
+       pushl   %cs:_count
+       call    printlong
+       print   "  cs:"
+       pushw   %cs
+       call    printword
+       print   " ip:"
+       pushw   2(%bp)
+       call    printword
+       print   " ss:"
+       pushw   %ss
+       call    printword
+       print   " ebp:"
+       mov     %ebp, %eax
+       mov     0(%bp), %ax
+       pushl   %eax
+       call    printlong
+       print   " esp:"
+       mov     %esp, %eax
+       mov     %bp, %ax
+       add     $4, %ax
+       pushl   %eax
+       call    printlong
+       call    line
+
+       print   "eax:"
+       pushl   -8(%bp)
+       call    printlong
+       print   " ebx:"
+       pushl   -20(%bp)
+       call    printlong
+       print   " ecx:"
+       pushl   -12(%bp)
+       call    printlong
+       print   " edx:"
+       pushl   -16(%bp)
+       call    printlong
+       call    line
+
+       print   "ds:"
+       pushw   %ds
+       call    printword
+       print   " esi:"
+       pushl   -32(%bp)
+       call    printlong
+       print   " es:"
+       pushw   %es
+       call    printword
+       print   " edi:"
+       pushl   -36(%bp)
+       call    printlong
+       print   " fs:"
+       pushw   %fs
+       call    printword
+       print   " gs:"
+       pushw   %gs
+       call    printword
+       call    line
+
+       mov     -4(%bp), %eax
+       print   "ID VIP VIF AC VM RF NT IOPL OF DF IF TF SF ZF AF PF CF   EFLAGS\n"
+       print   " "
+       bt      $21, %eax
+       call    printbit
+       print   "   "
+       bt      $20, %eax
+       call    printbit
+       print   "   "
+       bt      $19, %eax
+       call    printbit
+       print   "  "
+       bt      $18, %eax
+       call    printbit
+       print   "  "
+       bt      $17, %eax
+       call    printbit
+       print   "  "
+       bt      $16, %eax
+       call    printbit
+       print   "  "
+       bt      $14, %eax
+       call    printbit
+       print   "   "
+       bt      $13, %eax
+       call    printbit
+       bt      $12, %eax
+       call    printbit
+       print   "  "
+       bt      $11, %eax
+       call    printbit
+       print   "  "
+       bt      $10, %eax
+       call    printbit
+       print   "  "
+       bt      $9, %eax
+       call    printbit
+       print   "  "
+       bt      $8, %eax
+       call    printbit
+       print   "  "
+       bt      $7, %eax
+       call    printbit
+       print   "  "
+       bt      $6, %eax
+       call    printbit
+       print   "  "
+       bt      $4, %eax
+       call    printbit
+       print   "  "
+       bt      $2, %eax
+       call    printbit
+       print   "  "
+       bt      $0, %eax
+       call    printbit
+       print   "  "
+       push    %eax
+       call    printlong
+       call    line
+
+       popal
+       popfl
+       leave
+       ret     $0
+
+# ndebug: sends cpu state to netword
+.globl ndebug
+ndebug:
+       enter   $0, $0
+       pushfl
+       pushal
+
+       pushl   %cs:_count
+       popl    %cs:_debug_count
+       mov     %cs, %cs:_debug_cs
+       pushw   2(%bp)
+       popw    %cs:_debug_ip
+       mov     %ss, %cs:_debug_ss
+       mov     %ebp, %eax
+       mov     0(%bp), %ax
+       mov     %eax, %cs:_debug_ebp
+       mov     %esp, %eax
+       mov     %bp, %ax
+       add     $4, %ax
+       mov     %eax, %cs:_debug_esp
+       pushl   -8(%bp)
+       popl    %cs:_debug_eax
+       pushl   -20(%bp)
+       popl    %cs:_debug_ebx
+       pushl   -12(%bp)
+       popl    %cs:_debug_ecx
+       pushl   -16(%bp)
+       popl    %cs:_debug_edx
+       mov     %ds, %cs:_debug_ds
+       pushl   -32(%bp)
+       popl    %cs:_debug_esi
+       mov     %es, %cs:_debug_es
+       pushl   -36(%bp)
+       popl    %cs:_debug_edi
+       mov     %fs, %cs:_debug_fs
+       mov     %gs, %cs:_debug_gs
+       pushl   -4(%bp)
+       popl    %cs:_debug_eflags
+
+       push    $0x0008
+       push    $_debug_undi_transmit_packet
+       call    api
+
+       popal
+       popfl
+       leave
+       ret     $0
+
+# step: turns on step debugging
+.globl step
+step:
+       enter   $0, $0
+       push    %eax
+       push    %es
+
+       xor     %ax, %ax
+       mov     %ax, %es
+       mov     %cs, %ax                # get segment
+       shl     $16, %eax               # offset by 16
+       mov     $_step, %ax             # get offset of step function
+       mov     %eax, %es:(4 * 0x1)     # save new int1 (step) vector
+       pushf                           # push eflags
+       pop     %ax                     # get flags in ax
+       or      $0x0100, %ax            # set the Trap Flag bit
+       push    %ax                     # push the new eflags back
+       popf                            # pop new eflags
+
+       pop     %es
+       pop     %eax
+       leave
+       ret     $0
+
+_step: enter   $0, $0
+//     push    %eax
+//     push    %ebx
+//     push    %ecx
+//     push    %si
+//     push    %ds
+       push    %es
+
+//     lds     2(%bp), %si
+//     cld
+//     lodsb
+//     cmp     $0x66, %al
+//     jne     0f
+//     lodsb
+//0:   cmp     $0x9d, %al              # next is popf or popfl
+//     jne     0f
+//     orw     $0x0100, 8(%bp)         # keep TR on (popped flags)
+pushf
+0:     orw     $0x0100, 6(%bp)         # keep TR on (own flags)
+popf
+//     mov     2(%bp), %eax
+
+       pushw   $0xb800
+       pop     %es
+//     xor     %ebx, %ebx
+//1:   mov     %eax, %ecx
+//     shr     $28, %ecx
+//     add     $'0', %cl
+//     cmp     $'9', %cl
+//     jbe     0f
+//     add     $('a' - '9' - 1), %cl
+//0:   mov     $0x07, %ch
+//     mov     %cx, %es:142(,%ebx,2)
+//     inc     %ebx
+//     cmp     $4, %ebx
+//     jne     0f
+//     movw    $0x073a, %es:142(,%ebx,2)
+//     inc     %ebx
+//0:   shl     $4, %eax
+//     cmp     $9, %ebx
+//     jne     1b
+
+       pop     %es
+//     pop     %ds
+//     pop     %si
+//     pop     %ecx
+//     pop     %ebx
+//     pop     %eax
+       leave
+       iret
diff --git a/src/pxe.asm/global.S b/src/pxe.asm/global.S
new file mode 100644 (file)
index 0000000..be24835
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+  Copyright 2006-2008, V.
+  For contact information, see http://winaoe.org/
+
+  This file is part of WinAoE.
+
+  WinAoE is free software: you can 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.
+
+  WinAoE is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with WinAoE.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "aoe.h"
+
+.globl _drive, _cylinders, _heads, _sectors, _size
+.globl _irq, _clientmac, _servermac, _major, _minor
+
+_drive:                .word   0
+_cylinders:    .long   0
+_heads:                .word   0
+_sectors:      .word   0
+_size:         .long   0
+
+_irq:          .word   0
+_clientmac:    .org    .+6, 0
+_servermac:    .org    .+6, 0
+_major:                .word   0
+_minor:                .word   0
diff --git a/src/pxe.asm/int13.S b/src/pxe.asm/int13.S
new file mode 100644 (file)
index 0000000..2e40f79
--- /dev/null
@@ -0,0 +1,373 @@
+/*
+  Copyright 2006-2008, V.
+  For contact information, see http://winaoe.org/
+
+  This file is part of WinAoE.
+
+  WinAoE is free software: you can 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.
+
+  WinAoE is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with WinAoE.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "aoe.h"
+
+#ifdef DEBUG
+#  define COUNT call count
+#  define CHECK call ndebug
+#else
+#  define COUNT
+#  define CHECK
+#endif
+
+_oldint13:
+       .long   0
+
+.globl int13init
+int13init:
+       enter   $0, $0
+       push    %es
+       pushw   $0
+       pop     %es
+       pushl   %es:(0x13 * 4)
+       popl    %cs:_oldint13
+       pushw   %cs
+       popw    %es:((0x13 * 4) + 2)
+       pushw   $int13
+       popw    %es:(0x13 * 4)
+       pop     %es
+       leave
+       ret     $0
+
+int13: enter   $0, $0
+       pushfl
+       pushal
+       push    %ds
+       push    %es
+       push    %fs
+       push    %gs
+       COUNT
+       CHECK
+
+       cmpb    %dl, %cs:_drive         # for our drive?
+       je      0f                      # if so, jump
+       pop     %gs
+       pop     %fs
+       pop     %es
+       pop     %ds
+       popal
+       popfl
+       pushf
+       lcall   *%cs:_oldint13          # old int13 vector
+       jmp     iret
+
+0:     cmp     $0x00, %ah              # reset disk
+       jne     0f
+       jmp     x00
+0:     cmp     $0x02, %ah              # read sectors
+       jne     0f
+       jmp     x02
+0:     cmp     $0x03, %ah              # write sectors
+       jne     0f
+       jmp     x03
+0:     cmp     $0x04, %ah              # verify sectors
+       jne     0f
+       jmp     x04
+0:     cmp     $0x08, %ah              # get parameters
+       jne     0f
+       jmp     x08
+0:     cmp     $0x15, %ah              # get disk type
+       jne     0f
+       jmp     x15
+0:     cmp     $0x18, %ah              # set media type for format
+       jne     0f
+       jmp     x18
+0:     cmp     $0x41, %ah              # extentions
+       jne     0f
+       jmp     x41
+0:     cmp     $0x42, %ah              # extended read
+       jne     0f
+       jmp     x42
+0:     cmp     $0x43, %ah              # extended write
+       jne     0f
+       jmp     x43
+0:     cmp     $0x48, %ah              # extended get parameters
+       jne     0f
+       jmp     x48
+0:     print   "Unknown int13 function (0x"
+       shr     $8, %ax
+       push    %ax
+       call    printbyte
+       print   ")\n"
+       halt
+
+iret:  CHECK
+       leave
+       lret    $2                      # iret, skip saved flags
+
+# reset disk
+# returns:
+#  clear cf on success
+x00:   pop     %gs
+       pop     %fs
+       pop     %es
+       pop     %ds
+       popal
+       popfl
+       clc
+       jmp     iret
+
+# read/write sectors
+#  al: number of sectors to read/write (must be nonzero)
+#  ch: low eight bits of cylinder number
+#  cl: sector number 1-63 (bits 0-5)
+#      high two bits of cylinder (bits 6-7)
+#  dh: head number
+#  dl: drive number
+#  es:bx: data buffer
+# returns:
+#  ah = 0 and clear cf on success
+x02:   pushw   $0                      # read
+       jmp     0f
+x03:   pushw   $1                      # write
+0:     push    %es                     # buffer high
+       push    %bx                     # buffer low
+       mov     %eax, %ebx
+       call    calculatelba            # get lba from registers (cx & dh)
+       push    %eax                    # lba
+       xor     %bh, %bh
+       push    %bx                     # count
+       call    processsectors
+       pop     %gs
+       pop     %fs
+       pop     %es
+       pop     %ds
+       popal
+       popfl
+       mov     $0, %ah
+       clc
+       jmp     iret
+
+# verify sectors
+x04:   pop     %gs
+       pop     %fs
+       pop     %es
+       pop     %ds
+       popal
+       popfl
+       mov     $0, %ah
+       clc
+       jmp     iret
+
+# get drive parameters
+#  dl: drive number
+# returns:
+#  ah = 0 and clear cf on success
+#  ch: low eight bits of maximum cylinder number
+#  cl: maximum sector number (bits 5-0)
+#      high two bits of maximum cylinder number (bits 7-6)
+#  dh: maximum head number
+#  dl: number of drives
+x08:   pop     %gs
+       pop     %fs
+       pop     %es
+       pop     %ds
+       popal
+       push    %eax
+       mov     %cs:_cylinders, %eax
+       cmp     $1023, %eax
+       jb      0f
+       mov     $1023, %ax
+0:     mov     %al, %ch
+       mov     %ah, %cl
+       shl     $6, %cl
+       or      %cs:_sectors, %cl
+       mov     %cs:_heads, %dh
+       dec     %dh
+       mov     $1, %dl                 # 1 drive
+       cmpb    $0x81, %cs:_drive
+       jne     0f
+       add     $1, %dl                 # another drive
+0:     pop     %eax
+       popfl
+       mov     $0, %ah
+       clc
+       jmp     iret
+
+# get disk type
+# returns:
+#  clear cf on success
+#  ah: type (3 = harddisk)
+#  cx:dx: number of sectors
+x15:   pop     %gs
+       pop     %fs
+       pop     %es
+       pop     %ds
+       popal
+       popfl
+       mov     $3, %ah
+       mov     %cs:_size + 2, %cx
+       mov     %cs:_size, %dx
+       clc
+       jmp     iret
+
+# set media type for format
+# ch: lower 8 bits of highest cylinder number
+# cl: sectors per track (bits 0-5)
+#     high 2 bits of cylinder number (bit 6+7)
+# returns:
+#  clear cf on success
+#  ah: status (1 = function not available)
+#  es:di: pointer to parameter table
+x18:   pop     %gs
+       pop     %fs
+       pop     %es
+       pop     %ds
+       popal
+       popfl
+       mov     $1, %ah
+       stc
+       jmp     iret
+
+# extentions
+# returns:
+#  clear cf on success
+#  ah: version (1)
+#  bx: 0xaa55
+#  cx: support map (0b001)
+x41:   pop     %gs
+       pop     %fs
+       pop     %es
+       pop     %ds
+       popal
+       popfl
+       mov     $1, %ah
+       mov     $0xaa55, %bx
+       mov     $0b001, %cx
+       clc
+       jmp     iret
+
+# extended read/write
+#  for write: al: write flags (bit 0: verify)
+#  ds:si: disk address packet
+#   (byte)0: size of packet (10h or 18h)
+#   (byte)1: reserved
+#   (word)2: count
+#   (long)4: buffer
+#   (longlong)8: lba
+# returns:
+#  ah = 0 and clear cf on success
+x42:   pushw   $0                      # read
+       jmp     0f
+x43:   pushw   $1                      # write
+0:     cmp     $0x10, (%si)            # check disk packet size
+       je      0f
+       cmp     $0x18, (%si)            # check disk packet size
+       je      0f
+       print   "Invalid disk packet size...\n"
+       halt
+0:     pushl   4(%si)                  # buffer
+       pushl   8(%si)                  # lba
+       pushw   2(%si)                  # count
+       call    processsectors
+       pop     %gs
+       pop     %fs
+       pop     %es
+       pop     %ds
+       popal
+       popfl
+       mov     $0, %ah
+       clc
+       jmp     iret
+
+# extended get parameters
+#  ds:si: drive parameters packet
+#   (word)0: packet size
+#   (word)2: information flags (3)
+#   (long)4: cylinders
+#   (long)8: heads
+#   (long)12: sectors
+#   (longlong)16: total size in sectors
+#   (word)24: bytes per sector
+# returns:
+#  ah = 0 and clear cf on success
+x48:   movw    $0x1a, 0(%si)
+       movw    $3, 2(%si)
+
+       pushl   %cs:_cylinders
+       popl    4(%si)
+       xor     %eax, %eax
+       mov     %cs:_heads, %al
+       mov     %eax, 8(%si)
+       mov     %cs:_sectors, %al
+       mov     %eax, 12(%si)
+       pushl   %cs:_size
+       popl    16(%si)
+       movw    $512, 24(%si)
+       pop     %gs
+       pop     %fs
+       pop     %es
+       pop     %ds
+       popal
+       popfl
+       mov     $0, %ah
+       clc
+       jmp     iret
+
+# calculatelba: calculates an lba from chs
+#  ch: low eight bits of cylinder number (0-1023)
+#  cl: sector number (1-63) (bits 0-5)
+#      high two bits of cylinder (0-1023) (bits 6-7)
+#  dh: head number (0-(HEADS - 1))
+# returns:
+#  lba in eax
+calculatelba:
+       enter   $0, $0
+       pushf
+       push    %ebx
+       push    %ecx
+       push    %edx
+       xor     %eax, %eax              # start with 0
+       mov     %ch, %al                # low cylinder part in al
+       mov     %cl, %ah                # high 2 bits of cylinderpart
+       shr     $6, %ah                 # shifted in ah (ax now has cylinder)
+       xor     %bx, %bx
+       mov     %cs:_heads, %bl         # heads
+       mul     %bx                     # cylinder * heads => dx:ax
+       shl     $16, %edx               # add highpart of mulw to eax
+       add     %edx, %eax              # eax now has cylinder * heads
+       pop     %edx
+       push    %edx
+       shr     $8, %edx                # set edx to headnumber
+       and     $0xff, %edx             # add headnumber to cylinder * heads
+       add     %edx, %eax              # and multiply by sectors per track
+       xor     %ebx, %ebx
+       mov     %cs:_sectors, %bl       # to get sector count in edx:eax
+       mul     %ebx                    
+       and     $0x3f, %ecx
+       add     %ecx, %eax              # add the low 6 bits of cl to eax
+       sub     $1, %eax                # substract by 1 (cl is 1 to 63)
+       cmp     $0, %edx                # check to see if dx truly is 0
+       je      0f
+       print   "calculate lba error, edx & eax: "
+       push    %edx                    # if edx was not 0, then input
+       call    printlong               # was somehow false, print and halt
+       call    space
+       push    %eax
+       call    printlong
+       call    line
+       halt
+0:     pop     %edx
+       pop     %ecx
+       pop     %ebx
+       popf
+       leave
+       ret     $0
diff --git a/src/pxe.asm/lib.S b/src/pxe.asm/lib.S
new file mode 100644 (file)
index 0000000..775d6cd
--- /dev/null
@@ -0,0 +1,413 @@
+/*
+  Copyright 2006-2008, V.
+  For contact information, see http://winaoe.org/
+
+  This file is part of WinAoE.
+
+  WinAoE is free software: you can 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.
+
+  WinAoE is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with WinAoE.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "aoe.h"
+
+# getticks: get ticks since midnight
+# returns:
+#  ticks in eax
+.globl getticks
+getticks:
+       enter   $0, $0
+       pushf
+       push    %cx
+       push    %dx
+       xor     %ah, %ah
+       int     $0x1a
+       mov     %cx, %ax
+       shl     $16, %eax
+       mov     %dx, %ax
+       pop     %dx
+       pop     %cx
+       popf
+       leave
+       ret     $0
+
+# getkey: gets a key with timeout
+#  (word)bp+4: timeout in ticks
+# returns:
+#  al: ascii value of key, 0 for timeout, change 13 (\r) to 10 (\n)
+.globl getkey
+getkey:
+       enter   $0, $0
+       pushf
+       push    %ebx
+       push    %eax
+       xor     %ebx, %ebx
+       mov     4(%bp), %bx
+       call    getticks
+       add     %eax, %ebx
+0:     mov     $1, %ah
+       int     $0x16
+       jnz     0f
+       call    getticks
+       cmp     %ebx, %eax
+       jb      0b
+       mov     $0, %al
+       jmp     1f
+0:     mov     $0, %ah
+       int     $0x16
+       cmp     $'\r', %al
+       jne     1f
+       mov     $'\n', %al
+1:     mov     %al, %bl
+       pop     %eax
+       mov     %bl, %al
+       pop     %ebx
+       popf
+       leave
+       ret     $2
+
+# printchar: prints a char
+#  (word)bp+4: char
+.globl printchar
+printchar:
+       enter   $0, $0
+       pushf
+       pushw   %ax
+       pushw   %bx
+       pushw   %dx
+       movb    4(%bp), %al
+       cmpb    $'\n', %al
+       jne     0f
+       pushw   $'\r'
+       call    printchar
+0:     movb    $0x0e, %ah
+       movb    4(%bp), %al
+       xorw    %bx, %bx
+       int     $0x10
+#ifdef SERIAL
+       pushfl
+       pushal
+//     movw    $0x00e3, %ax
+//     movw    $0x0000, %dx
+//     int     $0x14
+//     movb    $0x01, %ah
+//     movb    4(%bp), %al
+//     movw    $0x0000, %dx
+//     int     $0x14
+       popal
+       popfl
+#endif
+       pop     %dx
+       pop     %bx
+       pop     %ax
+       popf
+       leave
+       ret     $2
+
+.globl line, space, point, d0, d1, d2, d3, d4, d5, d6, d7, d8, d9
+# quick chars
+line:  push    $'\n'
+       jmp     0f
+space: push    $' '
+       jmp     0f
+point: push    $'.'
+       jmp     0f
+d0:    pushw   $'0'
+       jmp     0f
+d1:    pushw   $'1'
+       jmp     0f
+d2:    pushw   $'2'
+       jmp     0f
+d3:    pushw   $'3'
+       jmp     0f
+d4:    pushw   $'4'
+       jmp     0f
+d5:    pushw   $'5'
+       jmp     0f
+d6:    pushw   $'6'
+       jmp     0f
+d7:    pushw   $'7'
+       jmp     0f
+d8:    pushw   $'8'
+       jmp     0f
+d9:    pushw   $'9'
+0:     call    printchar
+       ret
+
+# printnumber: prints a decimal number
+#  (word)bp+4: number
+.globl printnumber
+printnumber:
+       enter   $0, $0
+       pushf
+       push    %ax
+       push    %bx
+       push    %cx
+       push    %dx
+       mov     4(%bp), %ax
+       xor     %cx, %cx
+       mov     $10, %bx
+0:     xor     %dx, %dx
+       div     %bx
+       add     $0x30, %dx
+       push    %dx
+       inc     %cx
+       cmp     $0, %ax
+       jne     0b
+0:     call    printchar
+       dec     %cx
+       jnz     0b
+       pop     %dx
+       pop     %cx
+       pop     %bx
+       pop     %ax
+       popf
+       leave
+       ret     $2
+
+# printlongnumber: prints a long decimal number
+#  (long)bp+4: number
+.globl printlongnumber
+printlongnumber:
+       enter   $0, $0
+       pushf
+       push    %eax
+       push    %ebx
+       push    %cx
+       push    %edx
+       mov     4(%bp), %eax
+       xor     %cx, %cx
+       mov     $10, %ebx
+0:     xor     %edx, %edx
+       div     %ebx
+       add     $0x30, %dx
+       push    %dx
+       inc     %cx
+       cmp     $0, %eax
+       jne     0b
+0:     call    printchar
+       dec     %cx
+       jnz     0b
+       pop     %edx
+       pop     %cx
+       pop     %ebx
+       pop     %eax
+       popf
+       leave
+       ret     $4
+
+# printbyte: prints a byte
+#  (word)bp+4: byte
+.globl printbyte
+printbyte:
+       enter   $0, $0
+       pushf
+       push    %ax
+       mov     4(%bp), %ax
+       shr     $4, %al
+       add     $0x30, %al
+       cmp     $0x3a, %al
+       jl      0f
+       add     $39, %al
+0:     push    %ax
+       call    printchar
+       mov     4(%bp), %ax
+       and     $0x0f, %al
+       add     $0x30, %al
+       cmp     $0x3a, %al
+       jl      1f
+       add     $39, %al
+1:     push    %ax
+       call    printchar
+       pop     %ax
+       popf
+       leave
+       ret     $2
+
+# printword: prints a word
+#  (word)bp+4: word
+.globl printword
+printword:
+       enter   $0, $0
+       pushf
+       push    %ax
+       mov     4(%bp), %ax
+       shr     $8, %ax
+       push    %ax
+       call    printbyte
+       push    4(%bp)
+       call    printbyte
+       pop     %ax
+       popf
+       leave
+       ret     $2
+
+# printlong: prints a long
+#  (long)bp+4: long
+.globl printlong
+printlong:
+       enter   $0, $0
+       pushf
+       push    %eax
+       mov     4(%bp), %eax
+       shr     $16, %eax
+       push    %ax
+       call    printword
+       push    4(%bp)
+       call    printword
+       pop     %eax
+       popf
+       leave
+       ret     $4
+
+
+# printbit: prints "1" if cf flag is set, else print "0"
+.globl printbit
+printbit:
+       enter   $0, $0
+       pushf
+       jc      0f
+       pushw   $'0'
+       call    printchar
+       jmp     1f
+0:     pushw   $'1'
+       call    printchar
+1:     popf
+       leave
+       ret     $0
+
+# printbits: prints a word in bits
+#  (word)bp+4: word
+.globl printbits
+printbits:
+       enter   $0, $0
+       pushf
+       push    %ax
+       push    %cx
+       mov     4(%bp), %ax
+       mov     $16, %cx
+0:     shl     $1, %ax
+       call    printbit
+       loop    0b
+       pop     %cx
+       pop     %ax
+       popf
+       leave
+       ret     $2
+
+# printline: prints a '\0' terminated string, located right behind the call
+# return to the instruction behind the '\0'
+.globl printline
+printline:
+       enter   $0, $0
+       pushf
+       push    %ax
+       push    %ds
+       push    %si
+       push    %cs
+       pop     %ds     
+0:     mov     2(%bp), %si             # get character address
+       lodsb                           # load char string
+       mov     %si, 2(%bp)             # store back new return value
+       cmp     $0, %al                 # until we reach a '\0'
+       jz      0f
+       push    %ax
+       call    printchar
+       jmp     0b
+0:     pop     %si
+       pop     %ds
+       pop     %ax
+       popf
+       leave
+       ret     $0
+
+# printbuffer: prints a buffer
+#  (long)bp+6: buffer
+#  (word)bp+4: length
+.globl printbuffer
+printbuffer:
+       enter   $0, $0
+       pushf
+       push    %ax
+       push    %bx
+       push    %cx
+       push    %ds
+       push    %si
+
+       cld
+       lds     6(%bp), %si
+       xor     %bx, %bx
+2:     cmpw    $0, 4(%bp)
+       je      2f
+       push    %ds
+       call    printword
+       push    $':'
+       call    printchar
+       push    %si
+       call    printword
+       call    space
+
+       mov     4(%bp), %cx
+       cmp     $0x10, %cx
+       jb      0f
+       mov     $0x10, %cx
+
+0:     sub     %cx, 4(%bp)
+       push    %cx
+0:     call    space
+       lodsb
+       push    %ax
+       call    printbyte
+       loop    0b
+       pop     %ax
+
+       push    %ax
+       mov     $0x11, %cx
+       sub     %ax, %cx
+0:     print   "   "
+       loop    0b
+       pop     %cx
+
+       sub     %cx, %si
+1:     lodsb
+       cmp     $0x20, %al
+       ja      0f
+       mov     $'.', %al
+0:     push    %ax
+       call    printchar
+       loop    1b
+       call    line
+       inc     %bx
+       cmp     $20, %bx
+       jb      0f
+       print   "Press a key\n"
+1:     push    $0
+       call    getkey
+       cmp     $0, %al
+       je      1b
+       xor     %bx, %bx
+0:     jmp     2b
+
+2:     pop     %si     
+       pop     %ds
+       pop     %cx
+       pop     %bx
+       pop     %ax
+       popf
+       leave
+       ret     $6
+
+.globl haltcpu
+haltcpu:
+       sti                     # hlt to idle the cpu, which
+       hlt                     # saves power on laptops and
+       jmp     haltcpu         # is nice to cpu usage in vmware
diff --git a/src/pxe.asm/pxe.S b/src/pxe.asm/pxe.S
new file mode 100644 (file)
index 0000000..56d24d7
--- /dev/null
@@ -0,0 +1,832 @@
+/*
+  Copyright 2006-2008, V.
+  For contact information, see http://winaoe.org/
+
+  This file is part of WinAoE.
+
+  WinAoE is free software: you can 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.
+
+  WinAoE is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with WinAoE.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "aoe.h"
+
+_int:          .byte   0
+_tag:          .long   0
+_oldisr:       .long   0
+_api:          .long   0
+send:          .org    .+AoEsize, 0
+receive:       .org    .+AoEsize, 0
+
+_undi_get_information:                 # 0x000c
+       .word   0                       # PXENV_STATUS Status
+       .word   0                       # UINT16 BaseIo
+       .word   0                       # UINT16 IntNumber
+       .word   0                       # UINT16 MaxTranUnit
+       .word   0                       # UINT16 HwType
+       .word   0                       # UINT16 HwAddrLen
+       .org    .+16, 0                 # MAC_ADDR CurrentNodeAddress
+       .org    .+16, 0                 # MAC_ADDR PermNodeAddress
+       .word   0                       # SEGSEL ROMAddress
+       .word   0                       # UINT16 RxBufCt
+       .word   0                       # UINT16 TxBufCt
+
+_get_cached_info:                      # 0x0071
+       .word   0                       # PXENV_STATUS Status
+       .word   3                       # UINT16 PacketType
+       .word   0                       # UINT16 BufferSize
+       .long   0                       # SEGOFF16 Buffer
+       .word   0                       # UINT16 BufferLimit
+
+_undi_open:                            # 0x0006
+       .word   0                       # PXENV_STATUS status
+       .word   0                       # UINT16 OpenFlag
+       .word   3                       # UINT16 PktFilter
+       .org    .+(2 + (8 * 16)), 0     # t_PXENV_UNDI_MCAST_ADDRESS R_Mcast_Buf
+
+_undi_isr_start:                       # 0x0014
+       .word   0                       # PXENV_STATUS Status
+       .word   0                       # UINT16 FuncFlag
+       .word   0                       # UINT16 BufferLength
+       .word   0                       # UINT16 FrameLength
+       .word   0                       # UINT16 FrameHeaderLength
+       .long   0                       # SEGOFF16 Frame
+       .byte   0                       # UINT8 ProtType
+       .byte   0                       # UINT8 PktType
+
+_undi_isr:                             # 0x0014
+       .word   0                       # PXENV_STATUS Status
+       .word   0                       # UINT16 FuncFlag
+       .word   0                       # UINT16 BufferLength
+       .word   0                       # UINT16 FrameLength
+       .word   0                       # UINT16 FrameHeaderLength
+       .long   0                       # SEGOFF16 Frame
+       .byte   0                       # UINT8 ProtType
+       .byte   0                       # UINT8 PktType
+
+_undi_transmit_packet:                 # 0x0008
+       .word   0                       # PXENV_STATUS Status
+       .byte   0                       # UINT8 Protocol
+       .byte   0                       # UINT8 XmitFlag
+       .long   (send + AoEdstaddr)     # SEGOFF16 DestAddr
+       .long   _undi_TBD               # SEGOFF16 TBD
+       .org    .+(2 * 4), 0            # UINT32 Reserved[2]
+
+_undi_TBD:
+       .word   0                       # UINT16 ImmedLength
+       .long   send                    # SEGOFF16 Xmit
+       .word   0                       # UINT16 DataBlkCount
+       .org    .+(8 * 8), 0            # DataBlk DataBlock[8]
+
+.globl pxeinit
+pxeinit:
+       enter   $0, $0
+       movw    $0x5650, %ax            # Check for PXE extension
+       int     $0x1a
+       cmpw    $0x564e, %ax
+       je      0f                      # jump if PXE found
+       print   "PXE check failed...\n"
+       halt
+
+0:     lesw    %es:0x28(%bx), %bx      # get !PXE in es:bx
+       pushl   %es:0x10(%bx)           # get api entry point
+       popl    %cs:_api
+
+       push    $0x0006                 # open undi
+       push    $_undi_open
+       call    api
+       cmpw    $0, %ax
+       je      0f
+       print   "open undi failed\n"
+       halt
+
+0:     movw    %cs, %cs:_undi_TBD + 4
+       movw    %cs, %cs:_undi_transmit_packet + 6
+       movw    %cs, %cs:_undi_transmit_packet + 10
+       movw    %cs, %cs:_debug_undi_TBD + 4
+       movw    %cs, %cs:_debug_undi_transmit_packet + 6
+       movw    %cs, %cs:_debug_undi_transmit_packet + 10
+
+       pushw   $0x000c                 # get nic information
+       pushw   $_undi_get_information
+       call    api
+       cmpw    $0, %ax
+       je      0f
+       print   "get information failed\n"
+       halt
+
+0:     pushw   $0x0071                 # get dhcp information
+       pushw   $_get_cached_info
+       call    api
+       cmpw    $0, %ax
+       je      0f
+       print   "get dhcp information failed\n"
+       halt
+
+0:     movl    %cs:_undi_get_information + 12, %eax    # client mac (high 4)
+       movl    %eax, %cs:(send + AoEsrcaddr)
+       movl    %eax, %cs:_debug_srcaddr
+       movl    %eax, %cs:_clientmac
+       movw    %cs:_undi_get_information + 16, %ax     # client mac (low 2)
+       movw    %ax, %cs:(send + AoEsrcaddr + 4)
+       movw    %ax, %cs:_debug_srcaddr + 4
+       movw    %ax, %cs:_clientmac + 4
+       movw    %cs:_undi_get_information + 4, %ax      # irq
+       movb    %al, %cs:_irq
+       movw    $0xa288, %cs:(send + AoEprotocol)       # protocol
+       movb    $0x10, %cs:(send + AoEver)              # version 1
+
+       call    searchrootpath
+       pushl   %eax
+       call    readrootpath
+
+       leave
+       ret     $0
+
+# api: calls undi api
+#  (word)bp+6: function
+#  (word)bp+4: struct adress in cs
+# returns:
+#  ax passed on from api call
+.globl api
+api:   enter   $0, $0
+       pushfl
+       pushw   %cs
+       pushw   4(%bp)
+       pushw   6(%bp)
+       lcall   *%cs:_api
+       addw    $6, %sp
+       popfl
+       leave
+       ret     $4
+
+# searchrootpath: search root-path in dhcp packet
+# returns:
+#  eax: position of root-path in memory
+searchrootpath:
+       enter   $0, $0
+       pushw   %cx
+       pushw   %ds
+       pushw   %si
+
+       ldsw    %cs:(_get_cached_info + 6), %si # load ds:si with dhcp location
+       xorb    %ah, %ah
+       xorw    %cx, %cx
+       addw    $0xf0, %si              # offset si to point to dhcp options
+1:     incw    %cx
+       lodsb
+       cmpb    $0xff, %al
+       jne     0f
+2:     print   "No root-path found in DHCP options...\n"
+       halt
+0:     cmpb    $0x11, %al
+       je      0f
+       incw    %cx
+       lodsb
+       addw    %ax, %cx
+       addw    %ax, %si
+       cmpw    $0x1024, %cx
+       jb      1b
+       jmp     2b
+0:     movw    %ds, %ax
+       shll    $16, %eax
+       movw    %si, %ax
+
+       pop     %si
+       pop     %ds
+       pop     %cx
+       leave
+       ret     $0
+
+# readrootpath: read root-path from dhcp and sets packet data
+#  (long)bp+4: address of root-path
+readrootpath:
+       enter   $0, $0
+       push    %ax
+       push    %bx
+       push    %ds
+       push    %si
+
+       mov     4(%bp), %si
+       mov     6(%bp), %ds
+       lodsb
+       xor     %ah, %ah
+       add     %ax, %si
+       movb    $0, %ds:(%si)
+       sub     %ax, %si
+
+       call    5f                      # read spaces
+       lodsw                           # read "aoe:e"
+       or      $0x2020, %ax
+       cmp     $0x6f61, %ax            # 'oa'
+       jne     9f                      # general error
+       lodsw
+       or      $0x0020, %ax
+       cmp     $0x3a65, %ax            # ':e'
+       jne     9f                      # general error
+       lodsb
+       or      $0x20, %al
+       cmp     $'e', %al
+       jne     9f                      # general error
+
+       call    6f                      # read number
+       jc      7f                      # major error
+       mov     %ax, %cs:_major
+       xchg    %ah, %al
+       mov     %ax, %cs:(send + AoEmajor)
+
+       lodsb
+       cmp     $'.', %al
+       jne     9f                      # general error
+       call    6f                      # read number
+       jc      8f                      # minor error
+       cmp     $0, %ah
+       jne     8f                      # minor error
+       mov     %al, %cs:_minor
+       mov     %al, %cs:(send + AoEminor)
+
+       call    5f                      # read spaces
+       lodsb
+       cmp     $0, %al
+       jne     9f                      # general error
+       pop     %si
+       pop     %ds
+       pop     %bx
+       pop     %ax
+       leave
+       ret     $4
+
+# local: read spaces
+5:     push    %ax
+0:     lodsb
+       cmp     $' ', %al
+       je      0b
+       dec     %si
+       pop     %ax
+       ret
+
+# local: read number
+# returns number in %ax
+# carry set on error
+6:     lodsb
+       cmp     $'0', %al
+       jne     1f
+       lodsb
+       dec     %si
+       cmp     $'0', %al
+       jb      0f
+       cmp     $'9', %al
+       ja      0f
+       stc
+       ret
+0:     xor     %ax, %ax
+       clc
+       ret
+
+1:     dec     %si
+       push    %bx
+       push    %cx
+       push    %dx
+       xor     %ah, %ah
+       mov     $10, %bx
+       xor     %cx, %cx
+       xor     %dx, %dx
+
+0:     lodsb
+       cmp     $'0', %al
+       jb      1f
+       cmp     $'9', %al
+       ja      1f
+
+       push    %ax
+       mov     %cx, %ax
+       mul     %bx
+       cmp     $0, %dx
+       jne     0f
+       mov     %ax, %cx
+       pop     %ax
+       sub     $0x30, %al
+       add     %ax, %cx
+       jc      0f
+       jmp     0b
+
+0:     dec     %si
+       pop     %dx
+       pop     %cx
+       pop     %bx
+       stc
+       ret
+       
+1:     dec     %si
+       cmp     $0, %cx
+       jne     0f
+       pop     %dx
+       pop     %cx
+       pop     %bx
+       stc
+       ret
+
+0:     mov     %cx, %ax
+       pop     %dx
+       pop     %cx
+       pop     %bx
+       clc
+       ret     
+
+# local: errors
+7:     print   "root-path major out of range...\n"
+       halt
+8:     print   "root-path minor out of range...\n"
+       halt
+9:     print   "root-path misformed, should be \"aoe:e<major>.<minor>\"...\n"
+       halt
+
+
+.globl getdiskparameters
+getdiskparameters:
+       enter   $0, $0
+       push    %eax
+       push    %ebx
+       push    %edx
+
+       movl    $0xffffffff, %cs:(send + AoEdstaddr)    # broadcast
+       movw    $0xffff, %cs:(send + AoEdstaddr + 4)
+       movb    $0x1, %cs:(send + AoEcount)
+       movb    $0xec, %cs:(send + AoEcmd)      # IDENTIFY DEVICE
+       movw    $(AoEsize - 1024), %cs:_undi_TBD        # size
+       call    requestpacket
+
+       mov     %cs:(receive + AoEsrcaddr), %eax        # copy server mac
+       mov     %eax, %cs:(send + AoEdstaddr)
+       mov     %eax, %cs:(_servermac)
+       mov     %cs:(receive + AoEsrcaddr + 4), %ax
+       mov     %ax, %cs:(send + AoEdstaddr + 4)
+       mov     %ax, %cs:(_servermac + 4)
+
+       mov     %cs:(receive + AoEdata + 200), %eax     # copy max lba
+       cmp     $0, %eax
+       jne     0f
+       print   "Disk size 0?\n"
+       halt
+0:     mov     %eax, %cs:_size
+
+       movb    $0x1, %cs:(send + AoEcount)
+       movb    $0x24, %cs:(send + AoEcmd)      # READ SECTOR
+       movl    $0, %cs:(send + AoElba0)
+       movw    $0, %cs:(send + AoElba4)
+       movw    $(AoEsize - 1024), %cs:_undi_TBD        # size
+       call    requestpacket
+       mov     %cs:(receive + AoEdata + 510), %ax
+       cmp     $0xaa55, %ax
+       je      0f
+       xor     %ax, %ax
+       jmp     1f
+
+0:     mov     %cs:(receive + AoEdata + 446 + 12), %eax
+       cmp     $0, %ax
+       je      0f
+       mov     %cs:(receive + AoEdata + 446 + 5), %ax
+       jmp     1f
+
+0:     mov     %cs:(receive + AoEdata + 462 + 12), %eax
+       cmp     $0, %ax
+       je      0f
+       mov     %cs:(receive + AoEdata + 462 + 5), %ax
+       jmp     1f
+
+0:     mov     %cs:(receive + AoEdata + 478 + 12), %eax
+       cmp     $0, %ax
+       je      0f
+       mov     %cs:(receive + AoEdata + 478 + 5), %ax
+       jmp     1f
+
+0:     mov     %cs:(receive + AoEdata + 494 + 12), %eax
+       cmp     $0, %ax
+       je      1f
+       mov     %cs:(receive + AoEdata + 494 + 5), %ax
+
+1:     cmp     $0, %al
+       jne     0f
+       mov     $254, %al
+0:     inc     %al
+       mov     %al, %cs:_heads
+
+       and     $0x3f, %ah
+       cmp     $0, %ah
+       jne     0f
+       mov     $0x3f, %ah
+0:     mov     %ah, %cs:_sectors
+
+       xor     %ebx, %ebx
+       xor     %edx, %edx
+       mul     %ah
+       mov     %ax, %bx
+       mov     %cs:_size, %eax
+       div     %ebx
+       mov     %eax, %cs:_cylinders
+
+       pop     %edx
+       pop     %ebx
+       pop     %eax
+       leave
+       ret     $0
+
+
+# processsectors: reads or writes sectors
+#  (word)bp+14: mode (0 = read, 1 = write)
+#  (long)bp+10: buffer
+#  (long)bp+6: lba
+#  (word)bp+4: count
+.globl processsectors
+processsectors:
+       enter   $0, $0
+       push    %eax
+       push    %bx
+       push    %cx
+       push    %ds
+       push    %es
+       push    %si
+       push    %di
+
+       cmpw    $0x7f, 4(%bp)           # check for count > 0x7f (127)
+       jbe     0f
+       jmp     1f
+0:     cmpw    $0, 4(%bp)              # check for a count of 0
+       jne     2f
+1:     print   "Invalid sector count ("
+       push    4(%bp)
+       call    printnumber
+       push    $')'
+       call    printchar
+       call    line
+       halt
+
+2:     xor     %ax, %ax                # next, do 1 or 2 sectors?
+       cmpw    $1, 4(%bp)
+       je      0f
+       inc     %ax
+0:     inc     %ax
+
+       mov     14(%bp), %bx
+       movb    $0x24, %cs:(send + AoEcmd)      # 0x24 = READ SECTOR
+       cmp     $0, %bx
+       je      0f
+       addb    $0x10, %cs:(send + AoEcmd)      # 0x34 = WRITE SECTOR
+0:     pushl   6(%bp)                          # sector
+       popl    %cs:(send + AoElba0)
+       movw    $0, %cs:(send + AoElba4)
+       mov     %al, %cs:(send + AoEcount)
+       movw    $(AoEsize - 1024), %cs:_undi_TBD        # size
+       cmp     $0, 14(%bp)                     # read?
+       je      1f
+
+       mov     $512, %cx
+       cmpb    $2, %cs:(send + AoEcount)       # 2 sectors?
+       jne     0f
+       add     $512, %cx
+0:     add     %cx, %cs:_undi_TBD
+       mov     10(%bp), %si
+       mov     12(%bp), %ds
+       mov     $(send + AoEdata), %di
+       push    %cs
+       pop     %es
+       cld                             # positive direction
+       rep     movsb                   # copy data to packet
+1:     call    requestpacket
+
+       cmp     $1, 14(%bp)             # write?
+       je      1f
+       push    %cs
+       pop     %ds
+       mov     $(receive + AoEdata), %si
+       mov     $512, %cx
+       cmpb    $2, %cs:(send + AoEcount)       # 2 sectors?
+       jne     0f
+       add     $512, %cx
+0:     mov     10(%bp), %di
+       mov     12(%bp), %es
+       cld
+       rep     movsb
+
+1:     addl    $2, 6(%bp)              # next sectors
+       addw    $1024, 10(%bp)          # add 1024 to buffer
+       subw    $1, 4(%bp)              # count one down
+       jz      0f                      # no more sectors
+       subw    $1, 4(%bp)              # count down another
+       jnz     2b                      # get more sectors?
+
+0:     pop     %di
+       pop     %si
+       pop     %es
+       pop     %ds
+       pop     %cx
+       pop     %bx
+       pop     %eax
+       leave
+       ret     $12
+
+
+# requestpacket: sends request and waits for a reply
+requestpacket:
+       enter   $0, $0
+       push    %eax
+       push    %ebx
+       push    %ecx
+       push    %es
+
+       xorb    %bh, %bh
+       movb    %cs:_irq, %bl
+       cmpb    $0, %bl
+       je      1f
+
+       movb    $0, %cs:_int
+
+       pushw   $0x0000                 # set es to vector table segment
+       popw    %es
+       cmpb    $7, %bl
+       jbe     0f
+       addb    $(0x70 - 8 - 8), %bl
+0:     addb    $8, %bl
+       shlw    $2, %bx
+       pushl   %es:(%bx)
+       popl    %cs:_oldisr
+       pushw   %cs
+       pushw   $isr
+       popl    %es:(%bx)
+
+       xorb    %bh, %bh
+       movb    %cs:_irq, %bl
+       cmpb    $7, %bl
+       jbe     0f
+       subb    $8, %bl
+       inb     $0xa1
+       btrw    %bx, %ax
+       mov     $2, %bl
+0:     inb     $0x21
+       btrw    %bx, %ax
+       outb    $0x21
+
+1:     pushl   %cs:_tag
+       popl    %cs:(send + AoEtag)
+
+0:     call    getticks
+       mov     %eax, %ecx
+       push    $0x0008                 # transmit packet
+       push    $_undi_transmit_packet
+       call    api
+
+1:     call    getpacket
+       cmp     $1, %ax
+       je      0f
+       call    getticks
+       sub     $2, %eax
+       cmp     %eax, %ecx
+       ja      1b
+       jmp     0b
+
+0:     incl    %cs:_tag
+
+       xorb    %bh, %bh
+       movb    %cs:_irq, %bl
+       cmpb    $0, %bl
+       je      2f
+
+       xorb    %bh, %bh
+       movb    %cs:_irq, %bl
+       cmpb    $7, %bl
+       jbe     0f
+       subb    $8, %bl
+       inb     $0xa1
+       btsw    %bx, %ax
+       jmp     1f
+0:     inb     $0x21
+       btrw    %bx, %ax
+       outb    $0x21
+
+1:     pushw   $0x0000                 # set es to vector table segment
+       popw    %es
+       cmpb    $7, %bl
+       jbe     0f
+       addb    $(0x70 - 8 - 8), %bl
+0:     addb    $8, %bl
+       shlw    $2, %bx
+       pushl   %cs:_oldisr
+       popl    %es:(%bx)
+
+2:     pop     %es
+       pop     %ecx
+       pop     %ebx
+       pop     %eax
+       leave
+       ret     $0
+
+
+# getpacket: get a waiting packet, if any
+# returns:
+#  ax is 1 if packet received
+getpacket:
+       enter   $0, $0
+        pushl  %ebx
+
+       mov     $0, %ax
+       cmpb    $0, %cs:_irq
+       je      1f
+       cmpb    $0, %cs:_int
+       ja      2f
+       jmp     3f
+
+1:     movw    $1, %cs:_undi_isr + 2   # PXENV_UNDI_ISR_IN_START
+       push    $0x0014                 # undi isr
+       push    $_undi_isr
+       call    api
+       cmp     $0, %cs:_undi_isr + 2
+       jne     3f                      # not ours
+2:     call    processpacket
+       cmp     $1, %ax
+       jne     3f
+       mov     $0, %ax
+       cmpw    $0xa288, %cs:receive + AoEprotocol
+       jne     3f
+       mov     %cs:receive + AoEtag, %ebx
+       cmp     %cs:_tag, %ebx
+       jne     3f
+       mov     %cs:receive + AoEmajor, %bx
+       xchg    %bh, %bl
+       cmp     %cs:_major, %bx
+       jne     3f
+       mov     %cs:receive + AoEminor, %bl
+       cmp     %cs:_minor, %bl
+       jne     3f
+       mov     $1, %ax
+
+3:     popl    %ebx
+       leave
+       ret     $0
+
+
+_in:   .word   0
+# isr: checks if the interrupt is for us
+isr:
+       enter   $0, $0
+       pushfl
+       pushal
+       push    %ds
+       push    %es
+       push    %fs
+       push    %gs
+
+       bts     $0, %cs:_in
+       jnc     1f
+       mov     $3, %ax
+       int     $0x10
+       print   "reentrant\n"
+       halt
+       mov     $0x20, %al
+       cmp     $7, %cs:_irq
+       jbe     0f
+       outb    %al, $0xa0
+0:     outb    %al, $0x20
+
+       pop     %gs
+       pop     %fs
+       pop     %es
+       pop     %ds
+       popal
+       popfl
+       leave
+       iret
+
+1:     movw    $1, %cs:_undi_isr_start + 2     # PXENV_UNDI_ISR_IN_START
+       push    $0x0014                         # undi isr
+       push    $_undi_isr_start
+       call    api
+       cmp     $0, %ax
+       je      0f
+       print   "PXENV_UNDI_ISR_IN_START failed\n"
+       pushw   %cs:_undi_isr_start
+       call    printword
+       call    line
+       halt
+0:     cmp     $0, %cs:_undi_isr_start + 2
+       je      0f                              # ours
+       mov     $3, %ax
+       int     $0x10
+       print   "ISR error!\n"
+       halt
+       pop     %gs
+       pop     %fs
+       pop     %es
+       pop     %ds
+       popal
+       popfl
+       leave
+       ljmp    *%cs:_oldisr
+0:     mov     $0x20, %al
+       cmp     $7, %cs:_irq
+       jbe     0f
+       outb    %al, $0xa0
+0:     outb    %al, $0x20
+       movb    $1, %cs:_int
+       movw    $0, %cs:_in
+       pop     %gs
+       pop     %fs
+       pop     %es
+       pop     %ds
+       popal
+       popfl
+       leave
+       iret
+
+# processpacket: reads packet and checks packet, copy if ok
+# returns:
+#  ax = 1 if packet copied
+processpacket:
+       enter   $0, $0
+       push    %bx
+       push    %cx
+       push    %ds
+       push    %es
+       push    %si
+       push    %di
+
+print "i"
+       xorw    %bx, %bx
+       movw    $2, %cs:_undi_isr + 2   # PXENV_UNDI_ISR_IN_PROCESS
+       push    $0x0014                 # undi isr
+       push    $_undi_isr
+       call    api
+       cmp     $0, %ax
+       je      0f
+       print   "PXENV_UNDI_ISR_IN_PROCESS failed\n"
+       pushw   %cs:_undi_isr
+       call    printword
+       call    line
+       halt
+
+0:     cmpw    $0, %cs:_undi_isr + 2   # done
+       jne     0f
+       print   "ISR started, but nothing to process?\n"
+       jmp     9f
+
+0:     cmpw    $4, %cs:_undi_isr + 2   # busy
+       jne     0f
+       print   "b"
+       jmp     9f
+
+0:     push    %cs
+       pop     %es
+       mov     $receive, %di
+3:     cld
+       cmpw    $2, %cs:_undi_isr + 2   # transmit
+       je      1f
+
+0:     cmpw    $3, %cs:_undi_isr + 2   # receive
+       je      0f
+       print   "Unknown function?\n"
+       jmp     1f
+
+0:
+print "."
+       mov     %cs:_undi_isr + 4, %cx
+       mov     %cs:_undi_isr + 12, %ds
+       mov     %cs:_undi_isr + 10, %si
+       rep     movsb
+       mov     $1, %bx
+
+1:     movw    $3, %cs:_undi_isr + 2   # PXENV_UNDI_ISR_IN_GET_NEXT
+       push    $0x0014                 # undi isr
+       push    $_undi_isr
+       call    api
+       cmp     $0, %ax
+       je      0f
+       print   "PXENV_UNDI_ISR_IN_GET_NEXT failed\n"
+       pushw   %cs:_undi_isr
+       call    printword
+       call    line
+       halt
+
+0:     cmpw    $4, %cs:_undi_isr + 2   # busy
+       je      9f
+       cmpw    $0, %cs:_undi_isr + 2   # done
+       je      9f
+       jmp     3b
+
+9:print "o"
+       mov     %bx, %ax
+       pop     %di
+       pop     %si
+       pop     %es
+       pop     %ds
+       pop     %cx
+       pop     %bx
+       leave
+       ret     $0
diff --git a/src/pxe.c/Makefile b/src/pxe.c/Makefile
new file mode 100644 (file)
index 0000000..f31e19c
--- /dev/null
@@ -0,0 +1,68 @@
+CFLAGS := -O0
+CFLAGS += -nostdlib -fleading-underscore
+#CFLAGS += -DMINIMAL
+CFLAGS += -DSERIAL
+LDFLAGS := -nostdlib -static -T aoe.ld -s
+
+all: aoe.0
+
+clean:
+       rm -rf obj sizes.txt
+
+obj/asm.o: asm.S Makefile
+       @rm -rf obj/asm.o aoe.0
+       @mkdir -p obj
+       gcc $(CFLAGS) -Wall -c -o obj/asm.o asm.S
+
+obj/debug.o: debug.S Makefile
+       @rm -rf obj/debug.o aoe.0
+       @mkdir -p obj
+       gcc $(CFLAGS) -Wall -c -o obj/debug.o debug.S
+
+obj/main.s: main.c main.h asm.h pxe.h lib.h Makefile
+       @rm -rf obj/main.s obj/main.o aoe.0
+       @mkdir -p obj
+       gcc $(CFLAGS) -Wall -S -o obj/main.s main.c
+
+obj/main.o: obj/main.s Makefile
+       @rm -rf obj/main.o aoe.0
+       @mkdir -p obj
+       gcc $(CFLAGS) -Wall -c -o obj/main.o obj/main.s
+
+obj/pxe.s: pxe.c pxe.h asm.h Makefile
+       @rm -rf obj/pxe.s obj/pxe.o aoe.0
+       @mkdir -p obj
+       gcc $(CFLAGS) -Wall -S -o obj/pxe.s pxe.c
+
+obj/pxe.o: obj/pxe.s Makefile
+       @rm -rf obj/pxe.o aoe.0
+       @mkdir -p obj
+       gcc $(CFLAGS) -Wall -c -o obj/pxe.o obj/pxe.s
+
+obj/libasm.o: libasm.S Makefile
+       @rm -rf obj/libasm.o aoe.0
+       @mkdir -p obj
+       gcc $(CFLAGS) -Wall -c -o obj/libasm.o libasm.S
+
+obj/lib.s: lib.c lib.h asm.h printf.c Makefile
+       @rm -rf obj/lib.s obj/lib.o aoe.0
+       @mkdir -p obj
+       gcc $(CFLAGS) -Wall -S -o obj/lib.s lib.c
+
+obj/lib.o: obj/lib.s Makefile
+       @rm -rf obj/lib.o aoe.0
+       @mkdir -p obj
+       gcc $(CFLAGS) -Wall -c -o obj/lib.o obj/lib.s
+
+aoe.0: aoe.ld obj/asm.o obj/debug.o obj/main.o obj/pxe.o obj/libasm.o obj/lib.o Makefile
+       @rm -rf aoe.0
+       ld $(LDFLAGS) obj/asm.o obj/debug.o obj/main.o obj/pxe.o obj/libasm.o obj/lib.o -o obj/aoe
+       objcopy -O binary obj/aoe aoe.0
+       @if [ `expr \`find aoe.0 -printf "%s"\` % 2` == 0 ]; then echo -en "\0" >> aoe.0; fi
+       @find aoe.0 -printf "%f size: %s\n"
+ifneq ($(findstring msys,$(MACHTYPE)), msys)
+       @echo "readelf -s *.o | sort -nr > sizes.txt"
+       @readelf -s *.o | egrep "FUNC|OBJECT" | tr -s " " | cut -f 4,9 -d " " | sort -nr > sizes.txt
+else
+       @rm -rf sizes.txt
+endif
diff --git a/src/pxe.c/aoe.ld b/src/pxe.c/aoe.ld
new file mode 100644 (file)
index 0000000..7e9665c
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+  Copyright 2006-2008, V.
+  For contact information, see http://winaoe.org/
+
+  This file is part of WinAoE.
+
+  WinAoE is free software: you can 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.
+
+  WinAoE is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with WinAoE.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+SECTIONS {
+  /DISCARD/ : {*(.comment*)}
+  /DISCARD/ : {*(.note*)}
+  . = 0;
+  .text : {*(*)}
+
+}
+PROVIDE(_end = .);
diff --git a/src/pxe.c/asm.S b/src/pxe.c/asm.S
new file mode 100644 (file)
index 0000000..3bacc97
--- /dev/null
@@ -0,0 +1,726 @@
+/*
+  Copyright 2006-2008, V.
+  For contact information, see http://winaoe.org/
+
+  This file is part of WinAoE.
+
+  WinAoE is free software: you can 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.
+
+  WinAoE is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with WinAoE.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+.code16gcc
+
+//#define STACKSIZE 8192
+//#define STACKSIZE 16384
+#define STACKSIZE 32768
+//#define STACKSIZE 40960
+//#define STACKSIZE 49152
+#define print call _printline; .asciz
+#define halt jmp _halt
+#define debug call _debug
+
+.bss
+.globl _segment, _oldnmi, _oldint13, _gotisr, _irq, _timer
+_segment:
+       .long   0
+_oldnmi:
+       .long   0
+_oldint13:
+       .long   0
+_gotisr:
+       .long   0
+_irq:
+       .long   0
+_timer:
+       .long   0
+
+#ifndef __MINGW32__
+.type _segment, @object
+.type _oldnmi, @object
+.type _oldint13, @object
+.type _gotisr, @object
+.type _irq, @object
+.type _timer, @object
+.type _idtr, @object
+.size _segment, 4
+.size _oldnmi, 4
+.size _oldint13, 4
+.size _gotisr, 4
+.size _irq, 4
+.size _timer, 4
+.size _idtr, 6
+#endif
+
+_ss1:  .word   0
+_esp1: .long   0
+_ebp1: .long   0
+_ss2:  .word   0
+_esp2: .long   0
+_ebp2: .long   0
+_ss3:  .word   0
+_esp3: .long   0
+_ebp3: .long   0
+_ss4:  .word   0
+_esp4: .long   0
+_ebp4: .long   0
+_switchcount:
+       .word   0
+#ifndef __MINGW32__
+.type _ss1, @object
+.type _ebp1, @object
+.type _esp1, @object
+.type _ss2, @object
+.type _ebp2, @object
+.type _esp2, @object
+.type _ss3, @object
+.type _ebp3, @object
+.type _esp3, @object
+.type _ss4, @object
+.type _ebp4, @object
+.type _esp4, @object
+.size _switchcount, 2
+.size _ss1, 2
+.size _ebp1, 4
+.size _esp1, 4
+.size _ss2, 2
+.size _ebp2, 4
+.size _esp2, 4
+.size _ss3, 2
+.size _ebp3, 4
+.size _esp3, 4
+.size _ss4, 2
+.size _ebp4, 4
+.size _esp4, 4
+.size _switchcount, 2
+#endif
+
+
+.text
+.globl _start
+_start:
+       pushfl                          # save eflags
+       pushl   %eax                    # save eax
+       call    0f                      # pushl eip
+0:     popl    %eax                    # popl eip
+       subw    $0b, %ax                # offset by 0: to get _start adress
+       cmpw    $0x7c00, %ax            # did we start from 0x7c00?
+       je      0f                      # if not, print error
+       print   "\nip is not 0x7c00, can not continue...\n"
+       halt
+0:     movw    %cs, %ax                # get %cs
+       cmpw    $0x0000, %ax            # is %cs 0x0000?
+       je      0f                      # if not, print error
+       print   "\ncs is not 0x0000, can not continue...\n"
+       halt
+0:     popl    %eax                    # restore eax
+       popfl                           # restore eflags
+       jmp     $0x07c0, $0f            # realign cs:eip to let _start be 0
+
+0:     pushl   $0x00007c00             # set stack to below the boot code
+       movw    %sp, %bp                # use bp for lss (lss can't use sp)
+       lssw    (%bp), %sp              # setup new stack in one call
+       movw    %sp, %bp                # set correct bp
+
+       pushfl                          # push flags and used registers
+       pushal
+       pushw   %ds
+       pushw   %es
+
+       int     $0x12                   # get memory size in kb
+       shlw    $6, %ax                 # change to paragraphs
+       movw    $(_end + STACKSIZE + 15), %cx   # get total size
+       shrw    $4, %cx                 # change to round up paragraphs
+       subw    %cx, %ax                # calculate target segment
+       andw    $0xffc0, %ax            # round down to kb boundry
+       movw    %ax, %cs:_segment       # store target segment
+       shrw    $6, %ax                 # convert to kb
+       pushw   $0x0040                 # select bios area segment
+       popw    %es                     # to write free memory
+       movw    %ax, %es:0x0013         # at 0040:0013
+
+       pushw   %cs                     # set ds as cs to copy
+       popw    %ds                     # the current code segment
+       movw    %cs:_segment, %es       # point to target segment
+       xorw    %si, %si                # zero si
+       xorw    %di, %di                # zero di
+       movw    $_end, %cx              # get size in bytes
+       cld                             # copy forward
+       rep     movsb                   # into target segment
+
+       popw    %es                     # pop eflags and used registers
+       popw    %ds
+       popal
+       popfl
+       pushw   $0                      # push 0 for lret ahead
+       pushw   %cs:_segment            # push target segment
+       pushl   $0f                     # push offset in target segment
+       lret                            # long return into target segment
+
+0:     cli
+       call    _switchstack            # switch stack
+       call    _pushcpu                # push cpu struct
+       movzwl  %sp, %eax               # sp points to the pushed struct
+       pushl   %eax                    # push pointer for call to main
+       movw    %cs:_segment, %ds       # set correct ds
+       movw    %cs:_segment, %es       # set correct es
+       call    __main                  # jump to main
+       addw    $4, %sp                 # clean pointer from stack
+       call    _popcpu                 # pop cpu
+       call    _restorestack           # restore external stack
+       int     $0x13                   # read disk sector setup by main
+       jmp     $0x0, $0x7c00           # jump to bootsector
+#ifndef __MINGW32__
+.type _start, @function
+.size _start, .-_start
+#endif
+
+# printline: prints a '\0' terminated string, located right behind the call
+# return to the instruction behind the '\0'
+_printline:
+       pushl   %ebp                    # setup ebp and frame pointer
+       movl    %esp, %ebp
+       pushfl                          # save flags and registers
+       pushal
+       pushw   %ds
+       pushw   %es
+       pushw   %fs
+       pushw   %gs
+
+       pushw   %cs                     # set ds as cs
+       popw    %ds
+       xorl    %eax, %eax              # clean up eax
+       cld                             # read forward
+0:     movw    4(%bp), %si             # get character address
+       lodsb                           # load char string
+       movw    %si, 4(%bp)             # store back new return value
+       testb   %al, %al                # jump if we reach a '\0'
+       jz      0f
+       pushl   %eax                    # push char
+       call    _putchar                # print char
+       addw    $4, %sp                 # clean up stack
+       jmp     0b
+
+0:     popw    %gs                     # restore registers and flags
+       popw    %fs
+       popw    %es
+       popw    %ds
+       popal
+       popfl
+       popl    %ebp                    # restore ebp
+       ret
+#ifndef __MINGW32__
+.type _printline, @function
+.size _printline, .-_printline
+#endif
+
+.globl _int8
+_int8:
+       pushw   %ax
+       incl    %cs:_timer
+       mov     $0x20, %al
+       outb    %al, $0x20
+       popw    %ax
+.code16
+       iret
+.code16gcc
+#ifndef __MINGW32__
+.type _int8, @function
+.size _int8, .-_int8
+#endif
+
+.globl _isr
+_isr:
+       pushfl
+       pushal
+       pushw   %ds
+       pushw   %es
+       pushw   %fs
+       pushw   %gs
+       pushw   %bp
+       sub     $16, %sp
+       movw    %sp, %bp
+       movl    $0x10000, 0(%bp)
+       movl    $0, 4(%bp)
+       movl    $0, 8(%bp)
+       movl    $0, 12(%bp)
+       pushw   %ss
+       pushw   %bp
+       pushw   $0x0014                 # PXENV_UNDI_ISR
+.code16
+       lcall   *%cs:_apivector
+.code16gcc
+       addw    $6, %sp
+       testw   %ax, %ax
+       jnz     1f
+       cmpw    $1, 2(%bp)
+       jne     0f
+       print   "\n\nISR Not ours...\n"
+       halt
+0:     mov     $0x20, %al
+       cmp     $7, %cs:_irq
+       jbe     0f
+       outb    %al, $0xa0
+0:     outb    %al, $0x20
+       add     $16, %sp
+       popw    %bp
+       popw    %gs
+       popw    %fs
+       popw    %es
+       popw    %ds
+       popal
+       popfl
+       movl    $1, %cs:_gotisr
+.code16
+       iret
+.code16gcc
+1:     print   "\n\nPXENV_UNDI_ISR: "
+       movb    1(%bp), %bl
+       movb    %bl, %bh
+       shrb    $4, %bh
+       rorl    $16, %ebx
+       movb    0(%bp), %bl
+       movb    %bl, %bh
+       shrb    $4, %bh
+       andl    $0x0f0f0f0f, %ebx
+       mov     $4, %cx
+0:     roll    $8, %ebx
+       addb    $0x30, %bl
+       cmpb    $0x3a, %bl
+       jb      1f
+       addb    $0x27, %bl
+1:     pushl   %ebx
+       call    _putchar
+       add     $4, %sp
+       decw    %cx
+       jnz     0b
+       print   "\n"
+       halt
+#ifndef __MINGW32__
+.type _isr, @function
+.size _isr, .-_isr
+#endif
+
+.globl _int13
+_int13:
+       cli
+       pushfl
+       cmpb    $0x80, %dl
+       jne     1f
+       cmpb    $0x00, %ah
+       je      0f
+       cmpb    $0x02, %ah
+       je      0f
+       cmpb    $0x03, %ah
+       je      0f
+       cmpb    $0x04, %ah
+       je      0f
+       cmpb    $0x08, %ah
+       je      0f
+       cmpb    $0x15, %ah
+       je      0f
+       cmpb    $0x18, %ah
+       je      0f
+       cmpb    $0x41, %ah
+       je      0f
+       cmpb    $0x42, %ah
+       je      0f
+       cmpb    $0x43, %ah
+       je      0f
+       cmpb    $0x48, %ah
+       je      0f
+1:     popfl
+.code16
+       ljmp    *%cs:_oldint13
+.code16gcc
+0:     popfl
+       call    _switchstack
+       call    _pushcpu
+       movzwl  %sp, %eax
+       pushl   %eax
+       movw    %cs:_segment, %ds
+       movw    %cs:_segment, %es
+       call    __int13
+       addw    $4, %sp
+       call    _popcpu
+       call    _restorestack
+.code16
+       lret    $2
+.code16gcc
+#ifndef __MINGW32__
+.type _int13, @function
+.size _int13, .-_int13
+#endif
+
+.globl _pushcpu
+_pushcpu:
+       pushfl                          # push flags
+       subw    $36, %sp                # reserve stack for cpu structure
+       pushl   %ebp                    # setup ebp and frame pointer
+       movl    %esp, %ebp
+       pushl   44(%bp)                 # push return address
+       popl    8(%bp)                  # pop on the correct spot
+       pushl   40(%bp)                 # push stored eflags
+       popl    4(%bp)                  # pop on the correct spot
+       pushl   40(%bp)                 # push stored eflags again
+       popl    44(%bp)                 # pop in structure
+       movl    %eax, 40(%bp)           # save cpu state in structure
+       movl    %ebx, 36(%bp)
+       movl    %ecx, 32(%bp)
+       movl    %edx, 28(%bp)
+       movl    %esi, 24(%bp)
+       movl    %edi, 20(%bp)
+       movw    %ds, 18(%bp)
+       movw    %es, 16(%bp)
+       movw    %fs, 14(%bp)
+       movw    %gs, 12(%bp)
+       popl    %ebp                    # restore ebp
+       popfl                           # restore flags
+       ret
+#ifndef __MINGW32__
+.type _pushcpu, @function
+.size _pushcpu, .-_pushcpu
+#endif
+
+.globl _popcpu
+_popcpu:
+       pushl   %ebp                    # save ebp
+       movl    %esp, %ebp              # use bp to access stack
+       movl    36(%bp), %eax           # restore cpu state from structure
+       movl    32(%bp), %ebx
+       movl    28(%bp), %ecx
+       movl    24(%bp), %edx
+       movl    20(%bp), %esi
+       movl    16(%bp), %edi
+       movw    14(%bp), %ds
+       movw    12(%bp), %es
+       movw    10(%bp), %fs
+       movw    8(%bp), %gs
+       pushl   40(%bp)                 # push eflags
+       popl    36(%bp)                 # pop eflags
+       pushl   4(%bp)                  # push return address
+       popl    40(%bp)                 # pop return address
+       popl    %ebp                    # restore ebp
+       addw    $32, %sp                # delete cpu structure
+       popfl                           # restore flags
+       ret
+#ifndef __MINGW32__
+.type _popcpu, @function
+.size _popcpu, .-_popcpu
+#endif
+
+# increment switch count and switch stack if it was zero
+.globl _switchstack
+_switchstack:
+       pushfl                          #
+       cli                             #
+       popl    %cs:8f                  #
+       popl    %cs:9f                  #
+
+       cmpw    $0, %cs:_switchcount    #
+       jne     0f                      #
+       movw    %ss, %cs:_ss1           # save stack settings
+       movl    %ebp, %cs:_ebp1
+       movl    %esp, %cs:_esp1
+       movl    $_end, %ebp             # initialize ebp and esp to
+       leal    ((STACKSIZE / 4) * 1)(%ebp), %ebp       # STACKSIZE above code
+       movw    %cs:_segment, %ss       # switch stack to target segment
+       movl    %ebp, %esp
+       jmp     1f
+
+0:     cmpw    $1, %cs:_switchcount    #
+       jne     0f                      #
+       movw    %ss, %cs:_ss2           # save stack settings
+       movl    %ebp, %cs:_ebp2
+       movl    %esp, %cs:_esp2
+       movl    $_end, %ebp             # initialize ebp and esp to
+       leal    ((STACKSIZE / 4) * 2)(%ebp), %ebp       # STACKSIZE above code
+       movw    %cs:_segment, %ss       # switch stack to target segment
+       movl    %ebp, %esp
+       jmp     1f
+
+0:     cmpw    $2, %cs:_switchcount    #
+       jne     0f                      #
+       movw    %ss, %cs:_ss3           # save stack settings
+       movl    %ebp, %cs:_ebp3
+       movl    %esp, %cs:_esp3
+       movl    $_end, %ebp             # initialize ebp and esp to
+       leal    ((STACKSIZE / 4) * 3)(%ebp), %ebp       # STACKSIZE above code
+       movw    %cs:_segment, %ss       # switch stack to target segment
+       movl    %ebp, %esp
+       jmp     1f
+
+0:     cmpw    $3, %cs:_switchcount    #
+       jne     0f                      #
+       movw    %ss, %cs:_ss4           # save stack settings
+       movl    %ebp, %cs:_ebp4
+       movl    %esp, %cs:_esp4
+       movl    $_end, %ebp             # initialize ebp and esp to
+       leal    ((STACKSIZE / 4) * 4)(%ebp), %ebp       # STACKSIZE above code
+       movw    %cs:_segment, %ss       # switch stack to target segment
+       movl    %ebp, %esp
+       jmp     1f
+
+0:     print   "\n\nOut of stack pages...\n"
+       jmp     .
+       halt
+
+1:     incw    %cs:_switchcount        #
+       pushl   %cs:9f                  # restore return address
+       pushl   %cs:8f                  #
+       popfl                           #
+       ret
+8:     .long   0
+9:     .long   0
+#ifndef __MINGW32__
+.type _switchstack, @function
+.size _switchstack, .-_switchstack
+#endif
+
+# decrement switch count and switch stack if it reaches 0
+.globl _restorestack
+_restorestack:
+       pushfl                          #
+       cli                             #
+        popl   %cs:8f                  #
+       popl    %cs:9f                  #
+
+       cmpw    $4, %cs:_switchcount    #
+       jne     0f                      #
+       pushw   %cs:_ss4                # select segment 0 for new stack
+       pushl   %cs:_esp4               # set stack to below the boot code
+       movw    %sp, %bp                # use bp for lss (lss can't use sp)
+       lssl    (%bp), %esp             # setup new stack in one call
+       movl    %cs:_ebp4, %ebp         #
+       jmp     1f
+
+0:     cmpw    $3, %cs:_switchcount    #
+       jne     0f                      #
+       pushw   %cs:_ss3                # select segment 0 for new stack
+       pushl   %cs:_esp3               # set stack to below the boot code
+       movw    %sp, %bp                # use bp for lss (lss can't use sp)
+       lssl    (%bp), %esp             # setup new stack in one call
+       movl    %cs:_ebp3, %ebp         #
+       jmp     1f
+
+0:     cmpw    $2, %cs:_switchcount    #
+       jne     0f                      #
+       pushw   %cs:_ss2                # select segment 0 for new stack
+       pushl   %cs:_esp2               # set stack to below the boot code
+       movw    %sp, %bp                # use bp for lss (lss can't use sp)
+       lssl    (%bp), %esp             # setup new stack in one call
+       movl    %cs:_ebp2, %ebp         #
+       jmp     1f
+
+0:     cmpw    $1, %cs:_switchcount    #
+       jne     0f                      #
+       pushw   %cs:_ss1                # select segment 0 for new stack
+       pushl   %cs:_esp1               # set stack to below the boot code
+       movw    %sp, %bp                # use bp for lss (lss can't use sp)
+       lssl    (%bp), %esp             # setup new stack in one call
+       movl    %cs:_ebp1, %ebp         #
+       jmp     1f
+
+0:     print   "\n\nStack page error...\n"
+       halt
+
+1:     decw    %cs:_switchcount        #
+       pushl   %cs:9f                  # restore return address
+       pushl   %cs:8f                  #
+0:     popfl                           #
+       ret
+8:     .long   0
+9:     .long   0
+#ifndef __MINGW32__
+.type _restorestack, @function
+.size _restorestack, .-_restorestack
+#endif
+
+# _GETVECTOR: returns an interrupt vector from segment 0
+.globl _GETVECTOR
+_GETVECTOR:
+       pushl   %ebp                    # setup ebp and frame pointer
+       movl    %esp, %ebp
+       pushw   $0                      # select segment 0
+       popw    %fs                     # fs may be used in functions
+       movzbl  8(%bp), %eax            # get padded interrupt number
+       movl    %fs:(,%eax,4), %eax     # get vector in eax
+       popl    %ebp