summaryrefslogtreecommitdiffstats
path: root/private/ntos/boot/bootcode/hpfs/i386
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--private/ntos/boot/bootcode/hpfs/i386/buf.inc222
-rw-r--r--private/ntos/boot/bootcode/hpfs/i386/chain.inc7
-rw-r--r--private/ntos/boot/bootcode/hpfs/i386/const.inc201
-rw-r--r--private/ntos/boot/bootcode/hpfs/i386/dir.inc286
-rw-r--r--private/ntos/boot/bootcode/hpfs/i386/dirent.inc80
-rw-r--r--private/ntos/boot/bootcode/hpfs/i386/filemode.inc105
-rw-r--r--private/ntos/boot/bootcode/hpfs/i386/fnode.inc214
-rw-r--r--private/ntos/boot/bootcode/hpfs/i386/fsstat.inc66
-rw-r--r--private/ntos/boot/bootcode/hpfs/i386/macro.inc781
-rw-r--r--private/ntos/boot/bootcode/hpfs/i386/makefile6
-rw-r--r--private/ntos/boot/bootcode/hpfs/i386/misc.inc64
-rw-r--r--private/ntos/boot/bootcode/hpfs/i386/pinboot.asm727
-rw-r--r--private/ntos/boot/bootcode/hpfs/i386/sources38
-rw-r--r--private/ntos/boot/bootcode/hpfs/i386/superb.inc242
-rw-r--r--private/ntos/boot/bootcode/hpfs/i386/tables.inc201
-rw-r--r--private/ntos/boot/bootcode/hpfs/i386/usa/boothpfs.h517
-rw-r--r--private/ntos/boot/bootcode/hpfs/i386/usa/pinboot.inc30
-rw-r--r--private/ntos/boot/bootcode/hpfs/i386/volume.inc102
18 files changed, 3889 insertions, 0 deletions
diff --git a/private/ntos/boot/bootcode/hpfs/i386/buf.inc b/private/ntos/boot/bootcode/hpfs/i386/buf.inc
new file mode 100644
index 000000000..fe2eb8377
--- /dev/null
+++ b/private/ntos/boot/bootcode/hpfs/i386/buf.inc
@@ -0,0 +1,222 @@
+;static char *SCCSID = "@(#)buf.h 12.1 88/11/21";
+;** BUF.H - Buffer definitions
+;
+; HPFS Utilities
+; Peter A. Williams
+; Copyright 1988 Microsoft Corporation
+;
+; Modification history:
+; P.A. Williams 08/01/89 Added typedef BUFNODE and PBUFNODE.
+;
+
+;* Buffer Nodes
+;
+; When the comments talk about "buffer address" they're always
+; talking about the buffer header address. If we're talking
+; about the address of the data field of the buffer, we say
+; "buffer data".
+;
+; These buffer headers are also used as I/O request blocks for
+; the data in the buffer. The B_IOP field contains the
+; function. Sometimes we need an I/O request block which
+; isn't assocated with a buffer - for example, when we read
+; directly into an application's memory area. For this, we keep
+; a pool of I/O request blocks which are actually BUFNODE
+; structures, but they aren't associated with a buffer and the
+; B_ADDR field is used to hold the I/O target address.
+; These BUFNODEs have BF_IORQ in the flags field to distinguish
+; them from regular buffer headers.
+;
+; Note that we use the B_SUM field for debugging purposes. This is an
+; array of SPB words, each of which holds the CAS (high and low
+; 16 bits xored togehter) of one of the sectors. We can then check
+; this value to make sure that we're setting the dirty bits
+; correctly.
+;
+; NOTE - see the discussion on holding and locking at the end of
+; this file
+;
+
+BUFNODE struc
+
+ B_LRU db (size DCHDR) dup (?) ; LRU chain, if not BF_IORQ
+ B_LRUH dd ? ; address of LRU chain head if not locked/held
+ ; if lcoked/held, we're on that chain but
+ ; this guy points to it's regular chain
+ B_SEC dd ? ; VSector #
+ B_ADDR dd ? ; address of data
+ B_DCHN db (size DCHDR) dup (?) ; doubly linked list of dirty buffers
+ B_dirt db ? ; 1 bit per dirty sector
+ ; used to optimize the write. Non dirty
+ ; marked sectors may still be rewritten
+ B_iop db ? ; disk driver I/O operation
+ B_type db ? ; type of info
+ B_FLAG db ? ; flags
+ B_HCNT dw ? ; hold count
+ B_LCNT db ? ; lock count (really a flag, only 0 or 1
+ B_BADSEC db ? ; 1 bit per defective sector
+ B_next dd ? ; advisory address of next buffer content
+ ; always a buffer header addr, never 0
+ B_DADR dd ? ; address of routine to call when I/O is done
+
+ ; The following two fields are redefined
+ ; if BF_IORQ is set.
+ B_HASH db (size DCHDR) dup (?) ; sector hash chain
+ B_HTA dd ? ; address of entry in hash table
+
+ B_WAIT dd ? ; head of wait chain
+ifdef DEBUG
+ B_SUM dw 4 dup (?) ; holds checksum of buffer contents
+else
+ B_XTRA db 8 dup (?)
+endif
+
+; 64 byte boundary
+
+ B_LDTIME dd ? ; time (in ms/512) when buffer was last dirtied
+ B_FDTIME dd ? ; time (in ms/512) when buffer got first dirtied
+ B_LWWAIT dd ? ; head of lazy write wait chain
+ B_XTRA2 db 64-16 dup (?)
+BUFNODE ends
+
+;typedef struct BUFNODE BUFNODE;
+;typedef struct BUFNODE *PBUFNODE;
+
+BUFHDRSHIFT equ 7
+
+ifdef MASM
+ .errnz (size BUFNODE) - (1 SHL BUFHDRSHIFT)
+endif
+
+; Following are alternative offsets if BF_IORQ is set
+
+B_XFER equ (DWORD PTR B_HTA) ; holds transfer sec cnt
+B_NADR equ (DWORD PTR B_HASH) ; addr of client's NOTEREC
+B_NMSK equ (DWORD PTR B_HASH+4) ; notification mask
+ifdef MASM
+ .errnz (size DCHDR)-8 ; enough room for double map
+endif
+
+; B_FLAG bits
+
+BFL_LWLOCK equ 00000001h ; buffer is being lazy written in a block
+
+
+; B_type values
+
+BF_FREE equ 0 ; buffer is free (not in LRU list)
+BF_LRU equ 1 ; buffer in LRU list
+
+
+; Priority values for LRU placement
+
+BP_KEEP equ 0 ; Buffer contains future-usable data
+BP_NOOPINION equ 1 ; Buffer contains marginally useful data
+BP_TOSS equ 2 ; Buffer is unlikely to be used
+
+; NOTEREC - Notification Record
+;
+; Some callers may post several disk requests in parallel and
+; want to keep track of when they're *all* complete. I/O
+; request blocks (buffer headers w/o buffers) have fields to
+; allow this. The caller stores the address of his NOTEREC,
+; and when each request completes it clears it's associated bit.
+; When all of the bits clear the block chain in the NOTEREC
+; is woken.
+;
+; Note that there can be only one thread blocked on a NOTEREC
+; because the first guy to wakeup will return the NOTEREC to the
+; heap or whatever. This occurs naturally; unlike I/O to the
+; buffer cache, NOTERECs are used for direct I/O. If someone
+; else wants to do I/O to the same location and if record and file
+; locking allows that, then they'll get their own NOTEREC or
+; cache I/O request and have a horse race. NOTERECs are only used
+; to do file data I/O, all "filesystem" structures are manipulated
+; via the cache.
+;
+; The fields are DWORD, but only the low byte of the MSK and FLD
+; records are used for normal completion. The 3rd byte of NTR_FLD
+; (..FF....h) is used for error posting - these bits are
+; set if an irrecoverable error occured in the I/O.
+;
+
+NOTEREC struc
+ NTR_FLD dd ? ; the mask bit field
+ NTR_BLC dd ? ; head of the block chain
+ NTR_MSK dd ? ; next bit to set in NTR_FLD
+NOTEREC ends
+
+
+;* Holding and Locking
+;
+; LOCK means that the buffer contents are inconsistant/incorrect. No body
+; is allowed to look at the contents of the buffer. This is done
+; when we're reading in from the disk; we'll mark the buffer
+; with the VSector # (so that any other folks that want that sector
+; won't issue their own reads in parallel) but we mark it LOCKED
+; so that nobody looks at it's contents which aren't correct yet.
+;
+; LOCKed is pretty rare because most folks which are mucking
+; with a buffer have it back in a consistant state before they
+; allow a context switch.
+;
+; An important exception to this is directory manipulation -
+; directory splitting, etc. In this case, a flag has been set
+; on the directory itself (in SBDIR) so that no one will try to
+; look at the directory contents. The cache block which has the
+; inconsistant DIRBLK might also have sectors belonging to someone
+; else and those sectors can be accessed by other folks because
+; the buffer isn't locked. (We don't lock the directory and not
+; the block for this reason, it's a fallout. We lock the directory
+; because it's too mucky for people to "back out" if they're
+; searching down into a directory and find out that they've
+; reached an area which is being rebuilt. The rebuilding might
+; propigate up and change the unlocked higher DIRBLKs that this
+; other guy has already accessed... So we lock the whole directory,
+; and thus needn't bother locking the cache blocks themselves.
+;
+; HOLD means that the contents are valid, but the cache block must continue
+; to hold that data. Folks use this when they need to access
+; two different sectors at the same time. They HOLD one when
+; they read the other so that there's no chance that by the
+; time the 2nd read finishes the first one has been evicted.
+; This is much cheaper than remembering the first one's VSector
+; # and calling RDBUF N times as you transfer N words of info
+; between the two sectors.
+;
+; By definition only one guy can lock a buffer (the lock count should
+; go to a flag; it's already a flag on directorys) but the hold
+; value is a count, since multiple people can hold. (Like the
+; electrician's safety plate which allows multiple electricians
+; to lock a breaker OPEN so that it can't be closed until ALL are
+; done). (SBDIRs have a hold count for the same reason - folks
+; may yield while in a directory and don't want it to change out
+; from under them)
+;
+; We also use hold when we set dirty bits. The concern is that
+; if we're going to write something to a buffer, yield the CPU,
+; then write something else, we don't want to have to make two
+; calls to SetDirt, one after each write. This costs time, and
+; also it would be a waste if the lazywriter were to write this
+; guy anyhow, since he's going to get dirty again ASAP and
+; writing him out doesn't free the cache block anyway, since it's
+; held.
+;
+; So my current algorithm is that I won't lazywrite anybody who
+; is held, and therefore won't mark them clean. This means,
+; in effect, that there is no ordering constraint on dirtying
+; a buffer or marking it dirty so long as it is held the entire
+; time. I think that the code now always marks it dirty before
+; a yield, even if held, because the debug code is a bit hard
+; assed about it, but this could be relaxed under the current
+; lazywrite rules I've just described.
+;
+; Both in the case of directorys and cache blocks, the theory is that
+; since these buffers are MRU, it's extremely rare that we'd actually try
+; to reclaim their buffer slots, and in general it's rare that there's
+; a conflict in their use. So in actual execution, these locks are
+; very rarely encountered. They're cheap - INC to set and DEC to clear,
+; so almost always all we're doing is INCing and DECing a location
+; and it's just two wasted instructions. Once in a while, though,
+; it's a big bacon save, as they say.
+;
diff --git a/private/ntos/boot/bootcode/hpfs/i386/chain.inc b/private/ntos/boot/bootcode/hpfs/i386/chain.inc
new file mode 100644
index 000000000..b1528c2a1
--- /dev/null
+++ b/private/ntos/boot/bootcode/hpfs/i386/chain.inc
@@ -0,0 +1,7 @@
+;static char *SCCSID = "@(#)chain.h 12.1 88/11/21";
+;* Doubly Chained Definitions
+
+DCHDR struc
+ FWD dd ? ; forward pointer
+ BAK dd ? ; backward pointer
+DCHDR ends
diff --git a/private/ntos/boot/bootcode/hpfs/i386/const.inc b/private/ntos/boot/bootcode/hpfs/i386/const.inc
new file mode 100644
index 000000000..5304fabfe
--- /dev/null
+++ b/private/ntos/boot/bootcode/hpfs/i386/const.inc
@@ -0,0 +1,201 @@
+;static char *SCCSID = "@(#)const.h 12.3 89/09/19";
+; #define DEBUG 1
+
+
+;* Constants for File System
+
+MAXPATH equ 256 ; maximum path length
+GROWDELT equ 8
+MVPFXSIZE equ 2 ; Size of the multivolume pathname prefix
+
+; Sector sizes
+
+SECSIZE equ 512 ; 512 bytes per sector
+SECSHIFT equ 9 ; 2^9 = SECSIZE
+SECMSK equ 01ffh ; sector size mask
+
+ifdef MASM
+ .errnz SECSIZE-512 ; C code uses 512 as a magic number - grep them out
+endif
+
+; Cache Sizes
+
+SPB equ 4 ; sectors per buffer
+SPB4 equ 1
+
+ifdef SPB4
+SPBMASK equ 3 ; mask for SPB
+SPBSHIFT equ 2
+SPBBITS equ 0fh ; SPB number of one bits, low order
+endif
+
+ifdef SPB8
+SPBMASK equ 7 ; mask for SPB
+SPBSHIFT equ 3
+SPBBITS equ 0ffh ; SPB number of one bits, low order
+endif
+
+ifdef OLD_CACHE
+BUFCNT equ 8
+endif
+
+BMASK equ SPB*SECSIZE-1 ; mask offset in to cache block
+BSHIFT equ SECSHIFT+SPBSHIFT
+
+LWBUFCT equ 16 ; size of reblocking lazy write buffer
+
+; OFT Hash Table Size (8 bytes each)
+
+OFTHASHCNT equ 16 ; 16 hash chains for open files
+OFTHASHMSK equ 78h ; mask for computing hash offset
+
+
+; Number of I/O command blocks which aren't associated with buffers
+
+IOBCNT equ 8 ; 8 should be enough BUGBUG
+
+; # of OS/2 ram semaphores that we can be blocked on, simultaneously.
+
+SEMCNT equ 32
+
+
+; Cache Hash
+;
+; A sector hash is used to locate the start of a chain, the chain
+; is then scanned linearly.
+;
+; For our current size of 256 hash chains, we get:
+;
+; 1 meg of cache RAM = 256 blocks = 1 blocks per chain (average)
+; 2 meg of cache RAM = 512 blocks = 2 blocks per chain (average)
+;
+
+HASHCNT equ 256 ; 1024 bytes of hash header
+
+; Directory Lookaside record count
+
+DLCNT equ 10 ; 10 guys for now
+
+; Maximum DIRBLKs we may need to allocate for any given
+; operation. This is in effect the maximum tree depth.
+;
+; Worst case, with 256 character file names and nearly empty
+; DIRBLKs, 10 is enough levels for 60,000 files - about 40 megabytes
+; of space just for that directory. Given more practical file length
+; names this is enough for 10s of millions of files in a directory.
+;
+
+MAX_DIR_NEED equ 10
+
+
+;* Heap Definitions
+
+HHSIZ equ 4 ; size, in bytes, of heap header
+GROHEAPCNT equ 50 ; grow heap if we have to compact more
+ ; than once per 50 allocations
+
+;* Special Transition Locking Structure size
+
+TRANCNT equ 4 ; just need 4 spots
+
+
+; Zero offset
+;
+; MASM won't take 0.BAK, so we use ZERO.BAK
+;
+
+dumy struc
+ ZERO db ?
+dumy ends
+
+
+; Maximum number of volumes that we can mount
+;
+; The volume ID is kept in the high bits of the sector numbers
+; kept in our RAM structures,
+; so there is a tradeoff between max volumes and max sectors.
+;
+; 32 max volumes gives us a 65 billion byte volume limit,
+; which should last us for a while. Since sector numbers
+; are stored on the disk without their volume upper bits
+; this is strictly an implimentation detail; we can adjust
+; the number of volumes or eliminate this tradeoff in other
+; implimentations which will be 100% media compatable.
+;
+; We use the term VSector to indicate a vol/sector combination
+; and PSector to indicate just the physical absolute sector #
+;
+;
+
+VOLMAX equ 32 ; 64 max volumes.
+
+MAXSEC equ 134217728 ; 2^32/32 max sectors
+
+SECMASK equ 07FFFFFFh ; mask for sector number
+
+HSECMASK equ 07h ; high byte sector mask
+
+HVOLMASK equ 0f8h ; high byte volume mask
+SVOLMASK equ 1fh ; shifted right volume mask
+
+VOLRSHIFT equ (32-5) ; shift right to extract volume index
+VOLLSHIFT equ 5 ; shift left to extract volume index
+
+
+;* Signature Values for Disk Structures
+;
+; These signature values help with debugging and they'll
+; be used by the CHKDSK utility to help repair disks.
+;
+; WARNING - the low byte of all valid signatures must be non-zero,
+; since we destroy signatures by clearing the low byte.
+
+J equ ((('J'-'A')*40+('G'-'A'))*40+'L'-'A')
+R equ ((('R'-'A')*40+('P'-'A'))*40+'W'-'A')
+
+ifdef MASM
+ABSIGVAL equ J*40*40*40 + R ; allocation blk
+DBSIGVAL equ 40000000h + J*40*40*40 + R ; directory blks
+FNSIGVAL equ 0C0000000h + J*40*40*40 + R ; fnodes
+else
+ABSIGVAL equ (long)J*40*40*40 + (long)R ; allocation blk
+DBSIGVAL equ 40000000hL + (long)J*40*40*40 + (long)R ; directory blks
+OLDFNSIGVAL equ 80000000hL + (long)J*40*40*40 + (long)R ; fnodes
+FNSIGVAL equ 0C0000000hL + (long)J*40*40*40 + (long)R ; fnodes
+endif
+
+
+
+;* FastFile bitmaps
+;
+; 0x00000000 all checking disabled
+; 0x00000001 FF_FLUSHLAZY DoZap lazy writes are automatically flushed
+; 0x00000002 FF_ZAPSEC DoZap blasts sector numbers/sector data
+; 0x00000004 FF_LRUCHK vbs verification of LRU/dirty integrity
+; 0x00000008 FF_CHKSUM sector checksumming is omitted
+; 0x00000010 FF_PLACECHK placebuf verifies location of buffer
+; 0x00000020 FF_HEAPCHK verify heap headers
+; 0x00000040 FF_DIRMAP produce inram map of directory tree
+; 0x00000080 FF_HASHCHN check hash chains
+;
+
+FF_FLUSHLAZY equ 00000001h
+FF_ZAPSEC equ 00000002h
+FF_LRUCHK equ 00000004h
+FF_CHKSUM equ 00000008h
+FF_PLACECHK equ 00000010h
+FF_HEAPCHK equ 00000020h
+FF_DIRMAP equ 00000040h
+FF_HASHCHN equ 00000080h
+
+; Dependency dumys.
+;
+; The assembler won't to an ".errnz" comparing two external
+; addresses, since it doesn't know their address. So we
+; put the .errnz in the module which defines the address,
+; and we make that location and all folks that rely upon the
+; relationship reference that dumy.
+;
+; If you change a relationship with such a dumy definition, you
+; must find and edit all references to this dumy.
+;
diff --git a/private/ntos/boot/bootcode/hpfs/i386/dir.inc b/private/ntos/boot/bootcode/hpfs/i386/dir.inc
new file mode 100644
index 000000000..9e2d44469
--- /dev/null
+++ b/private/ntos/boot/bootcode/hpfs/i386/dir.inc
@@ -0,0 +1,286 @@
+;** DIR.H - Dirblk and Dirent definitions
+;
+; FILESYS
+; Gregory A. Jones
+; Copyright 1988 Microsoft Corporation
+;
+; Modification history:
+; P.A. Williams 06/01/89 Replaced field DIR_USECNT with fields
+; DIR_FLEX and DIR_CPAGE. Added DF_NEEDEAS
+; define.
+; P.A. Williams 07/10/89 Add define DF_NEWNAME for "new" hpfs file
+; names.
+; P.A. Williams 07/14/89 Added typedefs for DIRENT and DIRBLK.
+; P.A. Williams 07/21/89 Converted DIRSIZP form ASM defn to C defn.
+;
+
+ifdef MASM
+ include dirent.inc
+else
+attr_directory equ 10h
+endif
+
+
+; Directory Entry Fields
+;
+; Directory entries are always left as a multiple of 4
+; to speed up moves. The DIR_NAMA field is variable length,
+; the DIR_BTP field, if present, is the last dword in the record.
+; ACL information may be stored after the DIR_NAMA field but before
+; the DIR_BTP field so the DIR_BTP field must be located by going
+; backwards from the end of the record
+;
+; WARNING - Mkdir block copies some of these entries and
+; makes assumptions about which fields get copied. Check
+; mkdir if stuff is added.
+;
+
+DIRENT struc
+ DIR_ELEN dw ? ; length of this entry (including free space)
+ DIR_FLAG dw ? ; flags - low byte defined below
+ ; high byte holds the old attr_ FAT values
+ DIR_FN dd ? ; FNODE Sector
+ DIR_MTIM dd ? ; last modification time
+ DIR_SIZE dd ? ; file size
+
+ DIR_ATIM dd ? ; last access time
+ DIR_CTIM dd ? ; fnode creation time
+ DIR_EALEN dd ? ; bytes of extended attributes
+ DIR_FLEX db ? ; description of "flex" area,
+ ; following file name:
+ ; bits 0-2: # of ACEs in DE
+ ; bits 3-7: reserved
+ DIR_CPAGE db ? ; code page index on volume
+
+; the following fields have information specific to the name and directory
+; position of the file. This info is not propigated for a move/rename
+; That code uses DIR_NAML as a seperator - check MOVE if changes are
+; made to this structure
+
+ DIR_NAML db ? ; length of file name
+ DIR_NAMA db ? ; name goes here
+
+; ACL information may be stored here
+
+; long DIR_BTP; btree pointer to descendent DIRBLK record.
+ ; This is only present if DF_BTP is set.
+ ; This field is referenced from the end of
+ ; the record, not DIR_NAMA+DIR_NAML
+DIRENT ends
+
+
+ifdef MASM
+DIR_BTP equ dword ptr -4 ; referenced from the end of the record
+endif
+SIZE_DIR_BTP equ 4
+
+MAX_DIRACL equ 3 ; max of 3 ACLs in dirent
+DIRSIZL equ offset DIR_NAMA ; base size of leaf dir entry (minus name)
+DIRSIZP equ (size DIRENT+4) ; base size of dir entry with btree ptr w/o name
+
+MAX_DIRENT equ (DIRSIZP+255+MAX_DIRACL*(size (long))+10) ; max size of a DIRENT
+ ; (plus some slop)
+
+
+; Directory Block Definition
+;
+; The change count field is incremented every time we move any
+; of the entries in this block. For efficiency reasons, folks
+; remember the Sector # and offset of a directory entry, and the
+; value of the DB_CCNT field when that info was recorded.
+; If the DB_CCNT field is different then the remembered value,
+; then the entry offset is invalid and the entry should be
+; refound from the top. Note that when a directory block splits,
+; the old DIRBLK gets the old DB_CCNT field. Since
+; the new DIRBLK is previously unknown, it can have
+; any DB_CCNT value. We start with zero so that DB_CCNT
+; gives us a feel for the change rate in the directory.
+;
+
+DIRBLK struc
+ DB_SIG dd ? ; signature value
+ DB_FREP dd ? ; offset of first free byte
+ DB_CCNT dd ? ; change count (low order bit is flag)
+ ; =1 if this block is topmost
+ ; =0 otherwise
+ DB_PAR dd ? ; parent directory PSector # if not topmost
+ ; FNODE sector if topmost
+ DB_SEC dd ? ; PSector # of this directory block
+
+ DB_START db ? ; first dirent record goes here
+ DB_DUMY db 2027 dup (?) ; round out to 2048 bytes
+
+
+DIRBLK ends
+
+; BUGBUG - we should init DB_CCNT with a random value
+; to prevent a fakeout by deleting one directory
+; and then creating another (find sequences will
+; remember sector numbers and signatures...)
+
+
+; Maximum entries per directory.
+
+MAXDIRE equ (size DIRBLK- DB_START)/(size DIRENT)
+
+
+
+
+
+;* DIR_FLAG values
+;
+
+DF_SPEC equ 0001h ; special .. entry
+DF_ACL equ 0002h ; item has ACL
+DF_BTP equ 0004h ; entry has a btree down pointer
+DF_END equ 0008h ; is dumy end record
+DF_XACL equ 0040h ; item has explicit ACL
+DF_NEEDEAS equ 0080h ; item has "need" EAs
+DF_NEWNAME equ 4000h ; item name is of "new" pinball format
+
+DF_RMASK equ DF_ACL+DF_XACL ; only attributes preserved for rename
+
+ifdef MASM
+ .errnz DF_BTP - SIZE_DIR_BTP ; code uses this "coincidence"
+endif
+
+; Attributes which creation can specify
+
+DF_CMASK equ attr_read_only+attr_hidden+attr_archive
+
+; Directory Lookaside Structure
+;
+; We keep info on all directories that we've seen in SBDIR records
+; in RAM, but we keep the last N that we've seen in a special
+; DIRLOOK list in RAM.
+;
+
+DIRLOOK struc
+ DL_LNK db (size DCHDR) dup (?) ; forward and backwards link
+ DL_VSECVAL dd ? ; VOL_SECVAL value
+ DL_SUM dd ? ; checksum value
+ DL_NAM dd ? ; pointer to name string on heap
+ DL_SBD dd ? ; pointer to SBDIR structure
+DIRLOOK ends
+
+
+; Subdirectory Linkage Structure
+;
+; For every directory that we've seen on the disk we keep a
+; SBDIR record in ram, linked into a heirarchy which parallels
+; the disk heirarchy. We never discard these, so we end up
+; with a RAM copy of all the parts of the directory heirarchy
+; that the user is using.
+;
+; Each SBDIR entry is on a circular doubly linked chain of
+; siblings (directors with the same parent directory). If a
+; directory contains no subdirectories the SD_ENT field is 0.
+; If a directory has subdirectories, their SBDIR entries are
+; in turn in a SD_SIB chain and the SD_ENT field points to
+; one of those SBDIR entries.
+;
+; SBDIR contains a lock and a hold mechanism. A directory is
+; locked when it is being edited; no other threads may view it
+; until it is unlocked. A directory which is HELD is one which
+; is being accessed and can't be edited.
+;
+; The locking and holding algorithms are complicated by the fact
+; that we almost never block so we want to do our typical locking
+; and unlocking inline, without calls, and with minimum tests.
+; We do this with a held count, and bits for locked, lock pending,
+; and solo pending. (Solo means that a user wants sole access to
+; the structure. He'll continue to block until no one else is
+; using it. This is typically done to delete the structure)
+; Another bit is the OR of the lock pending and solo pending bits,
+; and is high order in the dword which encompases SD_HCNT so that
+; when folks release their SD_HCNT value they can simulatneously
+; test to see if there is a pending action.
+;
+; To Hold the SBDIR:
+; If it's not locked and doesn't have a lock pending,
+; increment hold count
+; else
+; block on it and retry.
+;
+; To Unhold the SBDIR:
+; decrement the HCNT field.
+; If SD_PND & (HCNT == 0)
+; wake up waiters.
+;
+; To lock the SBDIR:
+; If locked, block and retry.
+; If HCNT != 0
+; if (lock pending already set)
+; block and retry
+; set lock pending. Block until HCNT is zero.
+; set locked
+;
+; To unlock the SBDIR:
+; clear lock bit.
+; If the block list is non-zero, issue a wakeup.
+;
+; To Solo the SBDIR:
+; Keep blocking until no one else is blocked on it and
+; no one has it held or locked.
+;
+; General Considerations:
+; Anyone who blocks on an SBDIR because it's held must
+; be sure to set a pending bit and the SD_PND bit so
+; that the unhold operation will wake them up.
+;
+; Anyone who blocks on an SBDIR must increment the
+; SD_BCNT field to prevent a SOLO operation from yanking
+; the rug out from under them. SOLO can't depend upon
+; checking the lock list because a blanket wakeup may
+; have cleared the lock list. If the SOLO guy gets control
+; first he'll believe that he can have it.
+;
+;
+
+SBDIR struc
+ SD_FNW db (size DCHDR) dup (?) ; FNWORK (findnotify) chain
+ SD_SIB db (size DCHDR) dup (?) ; chain of siblings
+ SD_LRU db (size DCHDR) dup (?) ; LRU chain
+ SD_ENT dd ? ; pointer to a descendent, or 0
+ SD_PAR dd ? ; pointer to parent SBDIR, 0 if root
+ SD_SEC db (size SECPTR) dup (?) ; VSector and hint of top dirblk
+ SD_FNO dd ? ; FNODE # of directory
+ SD_SUM dd ? ; checksum of name string
+ SD_CNT dw ? ; # of subdirectories in this one
+ SD_OPEN dw ? ; count of # of guys that have this open
+
+; We sometimes inc/dec SD_HCNT as a dword to test the HO bit in SD_FLAG
+
+ ; the following three fields are used to
+ ; control access. They're identical in use
+ ; to the equivalent fields in OFT
+
+ SD_HCNT dw ? ; held count, has SDH_PND bit also
+ SD_DMYZERO db ? ; must be zero
+ SD_FLAG db ? ; flag byte, high order in SD_HCNT dword
+ SD_WAIT dd ? ; head of the wait chain
+ SD_FREEDCNT dd ? ; incremented each time we free a DIRBLK
+ ; for this guy. See RDE for details
+ SD_WCNT dw ? ; count of folks blocked on this
+ SD_FNDCNT dw ? ; count of active finds in this directory
+ SD_ATIME dd ? ; time of last access
+ SD_NAM dd ? ; address of name string
+ SD_ACL dd ? ; SBDIR ACL pointer, 0 if none
+ ; points to DWORD count, followed by ACEs
+ ; if low bit of address is 0, is heap space
+ ; if low bit is 1, is system memory
+
+SBDIR ends
+
+SD_ACL_LIM equ 1024 ; *SD_ACL lists bigger than this come from
+ ; system memory, smaller come from heap
+
+SDF_PND equ 80h ; lock pending bit
+SDF_RTP equ 20h ; restricted traversal permissions
+ ; =0 if anyone can traverse the dir
+SDF_REALLYBAD equ 10h ; directory is really bad
+SDF_IPR equ 08h ; SD_ACL has inherit records
+SDF_PSO equ 04h ; pending solo
+SDF_PLK equ 02h ; pending lock
+SDF_LCK equ 01h ; directory is locked against access
+ \ No newline at end of file
diff --git a/private/ntos/boot/bootcode/hpfs/i386/dirent.inc b/private/ntos/boot/bootcode/hpfs/i386/dirent.inc
new file mode 100644
index 000000000..1ba3f82df
--- /dev/null
+++ b/private/ntos/boot/bootcode/hpfs/i386/dirent.inc
@@ -0,0 +1,80 @@
+BREAK <Directory entry>
+
+; SCCSID = @(#)dirent.inc 12.5 89/07/14
+;
+; +-----------------------------+
+; | (11 BYTE) filename/ext | 0 0
+; +-----------------------------+
+; | (BYTE) attributes | 11 B
+; +-----------------------------+
+; | (8 BYTE) reserved | 12 C
+; +-----------------------------+
+; | (WORD) First cluster of EA | 20 14
+; +-----------------------------+
+; | (WORD) time of last write | 22 16
+; +-----------------------------+
+; | (WORD) date of last write | 24 18
+; +-----------------------------+
+; | (WORD) First cluster of file| 26 1A
+; +-----------------------------+
+; | (DWORD) file size | 28 1C
+; +-----------------------------+
+;
+; First byte of filename = E5 -> free directory entry
+; = 00 -> end of allocated directory
+; Time: Bits 0-4=seconds/2, bits 5-10=minute, 11-15=hour
+; Date: Bits 0-4=day, bits 5-8=month, bits 9-15=year-1980
+;
+
+dir_entry STRUC
+dir_name DB 11 DUP (?) ; file name
+dir_attr DB ? ; attribute bits
+dir_pad DB 8 DUP (?) ; reserved for expansion
+dir_EAhandle DW ? ; handle to Extended Attributes
+dir_time DW ? ; time of last write
+dir_date DW ? ; date of last write
+dir_firstfile DW ? ; first allocation unit of file
+dir_size_l DW ? ; low 16 bits of file size
+dir_size_h DW ? ; high 16 bits of file size
+dir_entry ENDS
+
+DIRENT_DELETED EQU 0E5h ; indicator of deleted file
+DIRENT_NOFEALIST EQU 0 ; Indicates no extended attributes
+
+
+;
+; Values for dir_attr
+;
+; attr_newfiles is used in the case of IFS to indicate that the type of file
+; being requested for findfirst/next is a "new" file i.e. long
+; name or a mixed-case name that the FAT FS does not support.
+;
+attr_read_only EQU 1h
+attr_hidden EQU 2h
+attr_system EQU 4h
+attr_volume_id EQU 8h
+attr_directory EQU 10h
+attr_archive EQU 20h
+attr_device EQU 40h ; This is a VERY special bit.
+ ; NO directory entry on a disk EVER
+ ; has this bit set. It is set non-zero
+ ; when a device is found by GETPATH
+
+attr_newfiles EQU 40h ; name is non-8.3. never set for FAT FS
+
+attr_all EQU attr_hidden OR attr_system OR attr_directory
+ ; OR of hard attributes for FINDENTRY
+
+attr_ignore EQU attr_read_only OR attr_archive OR attr_device
+ ; ignore these attributes during
+ ; search first/next
+
+attr_changeable EQU attr_read_only OR attr_hidden OR attr_system OR attr_archive
+ ; changeable via CHMOD
+
+attr_used EQU attr_read_only OR attr_hidden OR attr_system OR attr_volume_id OR attr_directory OR attr_archive OR attr_newfiles
+ ; We ignore the rest for $Creat due to LOTUS
+ ; passing in an attribute of 0x8000!!
+
+INV_3XBOX_SRCH_ATTRS EQU attr_newfiles ; we should not pass this bit
+ ; for FSDS from 3xbox.
diff --git a/private/ntos/boot/bootcode/hpfs/i386/filemode.inc b/private/ntos/boot/bootcode/hpfs/i386/filemode.inc
new file mode 100644
index 000000000..2e9165204
--- /dev/null
+++ b/private/ntos/boot/bootcode/hpfs/i386/filemode.inc
@@ -0,0 +1,105 @@
+; SCCSID = @(#)filemode.inc 12.6 89/04/26
+
+BREAK <Standard I/O assignments>
+
+stdin EQU 0
+stdout EQU 1
+stderr EQU 2
+stdaux EQU 3
+stdprn EQU 4
+
+BREAK <File modes - passed to open, stored in sf_mode or JFN_Flags>
+
+;
+; The OS/2 api calls DosOpen, DosSetFHandState, and DosQFHandState
+; all use a mode word parameter. Some of these values are stored
+; in the sft (system file table) in the field sf_mode. Others
+; are stored in the JFN flags (JFN_Flg_Ptr). The layout of
+; sf_mode and the word parameter for the call is the same. The
+; following EQU's are used to get to these values. The layout
+; of the word is:
+;
+; 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
+; D W F C R L L L I S S S M A A A
+;
+; with:
+; AAA (2-0): The Access mode (read only, etc.)
+; SSS (6-4): Sharing mode (deny write acces to others, etc.)
+; LLL (8-10): Locality of reference (sequential, random, etc.)
+; M (3) : Monitor open
+; I (7) : Not inherited by child
+; R (11): Rumored to be used by spooler. API caller must set
+; this to zero.
+; C (12): Advise device driver not to cache data. This is
+; stored in JFN flags.
+; F (13): Fail errors
+; W (14): write through
+; D (15): Direct access open
+;
+; The DosOpen2 and $Extended_Open2 calls has an additional word for
+; openmode. The layout of this word is
+;
+; 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
+; P U U U U U U U U U U U U U U U
+;
+; with:
+; P (15): Open physical disk (used by FDISK program). This bit
+; is set by procedure DevReturnHandle. API/INT21h
+; caller must set this bit to zero. This bit is stored
+; in sft.
+;
+; U : Unused anywhere. API caller must set these bits to
+; zero.
+;
+; NOTE: Please document all use of the openmode bits including those
+; that are internal to the kernel (e.g. the P bit).
+
+; wwwwxxxxyyyyzzzz
+; 5432109876543210
+open_access EQU 0000000000000111B
+open_for_read EQU 00h
+open_for_write EQU 01h
+open_for_both EQU 02h
+open_max EQU 02h
+open_for_exec EQU 03h ; open via internal exec call
+ ; (not available to API)
+
+open_monitor EQU 0000000000001000B
+
+open_sharing_mode EQU 0000000001110000B
+sharing_compat EQU 000H
+sharing_deny_both EQU 010H
+sharing_deny_write EQU 020H
+sharing_deny_read EQU 030H
+sharing_deny_none EQU 040H
+sharing_max EQU 040H ; max value for check_access_AX
+ ; (check_access_ax handles
+
+; these bits are for openmode
+open_no_inherit EQU 0000000010000000B ; Child does not inherit handle
+open_autofail EQU 0010000000000000B ; hard errors failed
+open_write_through EQU 0100000000000000B ; write through to disk
+open_direct EQU 1000000000000000B ; open of a device for direct access
+open_no_cache EQU 0001000000000000B ; don't cache data
+
+open_locality EQU 0000011100000000B ; locality of reference
+locality_unknown EQU 000H
+locality_sequential EQU 100H
+locality_random EQU 200H
+locality_semirandom EQU 300H
+
+; these bits are for openmode2 available to DosOpen2/$Extended_Open2
+;
+open2_phys_disk EQU 1000000000000000B ; open physical disk
+
+; Bits carried in SFT mode field (@PhysDisk)
+o_mode_in_sft EQU open_direct+open_monitor+open_sharing_mode+open_access+open_locality
+
+; Bits carried in JFN flags
+o_mode_in_flags EQU open_write_through+open_autofail+open_no_inherit+open_no_cache
+
+; Reserved bits
+o_mode_reserved EQU NOT (o_mode_in_sft+o_mode_in_flags)
+o_mode2_reserved equ -1 ; all bits are reserved
+
+SUBTTL
diff --git a/private/ntos/boot/bootcode/hpfs/i386/fnode.inc b/private/ntos/boot/bootcode/hpfs/i386/fnode.inc
new file mode 100644
index 000000000..af0207520
--- /dev/null
+++ b/private/ntos/boot/bootcode/hpfs/i386/fnode.inc
@@ -0,0 +1,214 @@
+;** FNODE.H - Fnode definitions
+;
+; FILESYS
+; Gregory A. Jones
+; Copyright 1988 Microsoft Corporation
+;
+; Modification history:
+; P.A. Williams 06/01/89 Added fields FN_ACLBASE and FN_NEACNT
+; to fnode.
+; P.A. Williams 08/01/89 Added typedef FNODE and PFNODE, ALBLK, PALBLK,
+; ALLEAF, PALLEAF, ALSEC, and PALSEC.
+;
+
+
+;* File Allocation Tracking
+;
+; File space is allocated as a list of extents, each extent as
+; large as we can make it. This list is kept in a B+TREE format.
+; Each B+TREE block consists of a single sector containing an
+; ALSEC record, except for the top most block. The topmost block
+; consists of just an ALBLK structure, is usually much smaller than
+; 512 bytes, and is typically included in another structure.
+;
+; The leaf block(s) in the tree contain triples which indicate
+; the logical to physical mapping for this file. Typically this
+; extent list is small enough that it is wholy contained in the
+; fnode ALBLK stucture. If more than ALCNT extents are required
+; then the tree is split into two levels. Note that when the
+; topmost B+TREE block is 'split' no actual split is necessary,
+; since the new child block is much bigger than the parent block
+; and can contain all of the old records plus the new one. Thus,
+; we can have B+TREEs where the root block contains only one
+; downpointer.
+;
+; The following rules apply:
+;
+; 1) if the file is not empty, there is at least one sector allocated
+; to logical offset 0. This simplifys some critical loops.
+;
+; 2) The last entry in the last node block contains a AN_LOF value of
+; FFFFFFFF. This allows us to extend that last leaf block
+; without having to update the node block.
+;
+; 3) For the node records, the AN_SEC points to a node or leaf
+; sector which describes extents which occur before that
+; record's AN_LOF value.
+;
+
+;* Allocation block structure
+;
+; Each allocation block consists of one of these. This may be
+; a small block imbedded in an FNODE or OFT structure, or it
+; may occupy a whole sector and be embedded in an ALSEC structure.
+;
+
+ALBLK struc
+ AB_FLAG db ? ; flags
+ AB_FLAG2 db 3 dup (?) ; unused - sometimes copied with AB_FLAG
+ AB_FCNT db ? ; free count - slots for ALLEAF or ALNODE
+ AB_OCNT db ? ; occupied count - # of ALLEAF or ALNODEs
+ AB_FREP dw ? ; offset to last item+1
+ ; ALLEAF or ALNODE records go here
+ALBLK ends
+
+ABF_NODE equ 80h ; if not a leaf node
+ABF_BIN equ 40h ; suggest using binary search to find
+ABF_FNP equ 20h ; parent is an FNODE
+ABF_NFG equ 01h ; not a flag, high order bit of AB_FREP
+
+; Allocation Node Structure
+;
+; These follow an ALBLK header for a node block
+
+ALNODE struc
+ AN_LOF dd ? ; logical offset (sectors
+ AN_SEC dd ? ; sector for guys < this
+ALNODE ends
+
+
+; Allocation Leaf Structure
+;
+; These follow an ALBLK header in a leaf block
+
+ALLEAF struc
+ AL_LOF dd ? ; logical sector offset (sectors)
+ AL_LEN dd ? ; length of extent (sectors)
+ AL_POF dd ? ; physical sector offset (sectors)
+ALLEAF ends
+
+
+;* Allocation Sector Structure
+;
+; Root ALBLK structures are contained within other structures,
+; such as the FNODE. When the B+TREE is more than one level,
+; though, the non-root nodes are each held in a sector.
+;
+; This structure defines that format
+;
+
+ALSEC struc
+ AS_SIG dd ? ; signature
+ AS_SEC dd ? ; sector # of this sector
+ AS_RENT dd ? ; parent sector # or FNODE #
+ AS_ALBLK db (size ALBLK) dup (?) ; ALBLK goes here
+ ; ALNODE or ALLEAF records start here
+ALSEC ends
+
+; # of bytes available for ALLEAF or ALNODE values. Size chosen
+; so an integral # of either structure fits
+
+ifdef MASM
+ASSIZ equ ((SECSIZE - size ALSEC)/24*24)
+ .errnz size ALLEAF-12
+ .errnz size ALNODE-8
+ .errnz (ASSIZ + AL_LOF + size AL_LOF + size ALBLK) GT 512 ; extra room for an AL_LOF value
+else
+ASSIZ equ ((SECSIZE - size ALSEC)/24*24)
+endif
+
+
+; AuxInfo Structure
+;
+; The FNODE contains two AuxInfo structures, one for ACLs and
+; one for EAs.
+;
+; These structures point to within FNODE storage and also
+; potentially point to an overflow area which is an ALBLK structure.
+; The AI_FNL stuff is stored in the FN_FREE area, the ACLs first
+; and the EAs second, any free space following. The start of the
+; EAs can be found by offseting FN_FREE with FN_ACL.AI_FNL
+;
+
+AUXINFO struc
+ AI_DAL dd ? ; non-fnode Disk Allocation length
+ AI_SEC dd ? ; sec # of first sec in extent or of ALSEC
+ AI_FNL dw ? ; length of fnode info
+ AI_DAT db ? ; non-zero if AI_SEC points to ALSEC
+AUXINFO ends
+
+;* Fnode block definition
+;
+; Every file and directory has an FNODE. The file location
+; stuff is only used for files; directories are kept in
+; a BTREE of DIRBLK records pointed to by FN_SEC[0].RSEC
+;
+
+ALCNT equ 8 ; 8 ALLEAF records in an FN_AT entry
+LEAFPERFNODE equ 8 ; 8 ALLEAF records in an FN_AT entry
+NODEPERFNODE equ 12 ; 12 ALNODE records in an FNODE.
+LEAFPERSEC equ 40 ; ALLEAF records in an allocation sector
+NODEPERSEC equ 60 ; ALNODE records in an allocation sector
+
+FNODE struc
+
+; The following file location information is copied into the OFT
+; and is used there during normal file access. The stuff in the
+; fnode record here may in fact be out of date for open files.
+; See the OFN_ in the OFT structure THESE TWO AREAS IN THE
+; RESPECTIVE RECORDS MUST HAVE IDENTICAL FORMATS.
+;
+; There are two kinds of location info: FNSCNT SPTR records
+; and then a single, double, triple, and quad indirect block pointer.
+; The "block threshold" means the first sector number which is
+; contained in that indirect block heirarchy. You use this
+; to quickly find out where to start looking.
+;
+
+ FN_SIG dd ? ; signature value
+
+; History tracking info for softer software
+
+ FN_SRH dd ? ; sequential read history
+ FN_FRH dd ? ; fast read history
+ FN_NAME db 16 dup (?) ; 1st 18 bytes of file name
+ FN_CONTFN dd ? ; fnode of directory cont. this file/dir
+
+; stuff not interesting once opened
+
+ FN_ACL db (size AUXINFO) dup (?) ; access ctl list aux info structure
+ FN_HCNT db ? ; count of valid history bits
+ FN_EA db (size AUXINFO) dup (?) ; ea aux info structure
+ FN_FLAG db ? ; FNODE flag byte
+
+ FN_AB db (size ALBLK) dup (?) ; allocation block structure
+ FN_ALREC db (ALCNT*size ALLEAF) dup (?) ; referenced from FN_AB
+ FN_VLEN dd ? ; length of valid data in file. if DIR_SIZE
+ ; is > FN_VLEN then the space inbetween
+ ; must be zapped before being shown to user
+ FN_NEACNT dd ? ; # of "need eas" in file
+
+; The following fields are unused in this release, they're for
+; future compatibility. When deleting files, if FN_EEL is non-zero
+; then FN_EEL sectors starting at FN_EEP must be released too.
+;
+
+ FN_UID db 16 dup (?) ; reserved for UID value
+ FN_ACLBASE dw ? ; FN_ACLBASE offset of 1st ACE in fnode
+ FN_SPARE db 10 dup (?); 10 more bytes emergency spares
+
+; Free pool. ACLs and EAs are stored here via the AUXINFO structure
+
+ FN_FREE db 316 dup (?) ; free space for perm and env list; perm list
+ ; comes first.
+FNODE ends
+
+
+ifdef MASM
+ .errnz AL_LOF ; verify validity of FN_DMY1 hack above
+ .errnz size AL_LOF-4
+endif
+
+; Fnode FN_FLAG bits
+
+FNF_DIR equ 01h ; is a directory fnode
diff --git a/private/ntos/boot/bootcode/hpfs/i386/fsstat.inc b/private/ntos/boot/bootcode/hpfs/i386/fsstat.inc
new file mode 100644
index 000000000..074030367
--- /dev/null
+++ b/private/ntos/boot/bootcode/hpfs/i386/fsstat.inc
@@ -0,0 +1,66 @@
+;static char *SCCSID = "@(#)fsstat.h 12.2 88/12/19";
+;** fsstat.h - file system statistics
+;
+
+CTHIST equ 10000
+
+FSSTAT struc
+ ST_OPEN dd ? ; count of OPEN calls
+ ST_CLOSE dd ? ; count of CLOSE calls
+ ST_READ dd ? ; count of READ calls
+ ST_WRITE dd ? ; count of WRITE calls
+
+ ST_DEL dd ? ; count of DELETE calls
+ ST_SEEK dd ? ; count of SEEK calls
+ ST_FINDF dd ? ; count of FINDF calls
+ ST_FINDN dd ? ; count of FINDN calls
+
+ ST_RD dd ? ; count of disk reads
+ ST_WR dd ? ; count of disk writes
+ ST_CRD dd ? ; count of cache read hits
+ ST_CWD dd ? ; count of cache write hits
+
+ ST_INVAL dd ? ; invalid LSD hints
+ ST_VALID dd ? ; valid LSD hints
+ ST_RDEH dd ? ; directory relocated
+ ST_RDEM dd ? ; directory adjusted
+
+ ST_SFB dd ? ; count of SFB calls
+ ST_VBR dd ? ; count of VBR calls
+ ST_CBR dd ? ; count of CBR calls
+ ST_AEX dd ? ; count of AddExt calls
+
+ ST_EFA dd ? ; files extended
+ ST_FLW dd ? ; FLW buffers written
+ ST_BRV dd ? ; bitmap read valid
+ ST_BRI dd ? ; bitmap read invalid
+
+ ST_BLSD dd ? ; blocked in LSD
+ ST_BRDB dd ? ; blcoked in rdb
+ ST_GFBI dd ? ; GFB interlock
+ ST_GFBW dd ? ; gfb waits
+
+ ST_LWR dd ? ; long writes
+ ST_GIB dd ? ; Getinbuf was successful
+ ST_HMIN dd ? ; heap minimum
+ ST_LWBW dd ? ; singletons output by lazy IO
+
+ ST_CLN dd ? ; clean blocks found by lazy IO
+ ST_LWW dd ? ; wakeups caused by lazy IO blocks
+ ST_QINFO dd ? ; Query info
+ ST_QIDIR dd ? ; query info on directory
+
+ ST_LWBLK dd SPB*LWBUFCT dup (?) ; Histogram of lazy write blocks
+
+; performance impact items
+
+ ST_DLRS dd ? ; directory locked forced restart
+ ST_ALSP dd ? ; count of allocation block splits
+ pad2 dd 3 dup (?)
+
+ ST_RSIZ dd 64 dup (?) ; Histogram of # sectors in read request
+ ST_WSIZ dd 64 dup (?) ; Histogram of # sectors in write request
+FSSTAT ends
+
+FS_GETSTAT equ 8004h
+FS_CLEAR equ 8005h
diff --git a/private/ntos/boot/bootcode/hpfs/i386/macro.inc b/private/ntos/boot/bootcode/hpfs/i386/macro.inc
new file mode 100644
index 000000000..153ab4fd9
--- /dev/null
+++ b/private/ntos/boot/bootcode/hpfs/i386/macro.inc
@@ -0,0 +1,781 @@
+; SCCSID = @(#)macro.inc 12.1 88/12/19
+
+;** Macros
+
+
+;* MASSUME - do an assume
+;
+; made into a macro to make screwing around during debuuing
+; easier
+;
+; Used by the file system code; not recommended for general
+; use. Will be taken out at end of project. BUGBUG
+
+
+MASSUME MACRO
+ ASSUME CS:CODE,DS:FLAT,ES:FLAT,SS:NOTHING
+ ENDM
+
+
+;* MENTER - Do an Enter
+;
+; made into a macro for better code, and to avoid problems
+; when USE16 (MASM doesn't generate the override)
+
+MENTER MACRO arg1,arg2
+ push ebp
+ mov ebp,esp
+ ifdif <arg1>,<0>
+ sub esp,arg1
+ endif
+ ENDM
+
+;* MLEAVE - do a Leave
+;
+; We need to generate the segment override in USE16, since
+; MASM won't do it
+
+MLEAVE MACRO
+ ifndef USE32
+ DB 66h
+ endif
+ leave
+ ENDM
+
+;* GetPathBuf - Allocates from the heap memory for the PathBuffer
+;
+; Enter: (eax) = size of the requested heap block (hvpb not included)
+; Exit: C clear:
+; (eax) = ptr to the heap block
+; C set: error no more heap space
+; Uses: eax, flags
+
+GetPathBuf MACRO
+ SAVE <EDI, ECX>
+ add eax, MVPFXSIZE+3+HHSIZ ; for hvpb, rounding and header
+ and al, 0fch ; round it to quad-boundary
+ifndef GHS_
+ EXTRN GHS_:near
+endif
+ call GHS_
+ RESTORE <ECX, EDI>
+ENDM
+
+;* FreePathBuf - Return PathBuffer to the Heap
+;
+;
+; Enter: (reg) = ptr to PathBuffer (that's (sizeof hvbp) after the
+; heap block address)
+; Exit: heap block released
+; Uses: reg
+
+FreePathBuf MACRO reg
+ sub reg, MVPFXSIZE ; (reg) now pts to the heap block
+ HeapChk reg
+ add dword ptr -4[reg],80000000h-4
+ENDM
+
+
+
+;* Assert - sanity checks (contolled by DEBUG switch)
+;
+; kind: one of OFT
+;
+; objs: register/word which contains address
+;
+; nopush: if non-blank, we don't preserve registers
+
+IFDEF DEBUG
+ASSERT MACRO kind, objs, nopush, arg1
+ local a
+
+a = 0
+
+
+ IFNDEF A_OFT
+ extrn A_OFT:near,A_SECPTR:near,A_DIRBLK:near,A_FNODE:near
+ extrn A_AS:near,A_HEAPNAM:near,A_DCHDR:near,A_BUF:near
+ extrn A_SBDIR:near,A_ALBLK:near
+ ENDIF
+
+ IFB <nopush>
+ pushad
+ pushfd
+ ENDIF
+
+ IFIDN <kind>,<OFT>
+ a = 1
+ mov eax,objs
+ call A_OFT ; assert OFT
+ ENDIF
+ IFIDN <kind>,<SECPTR>
+ a = 1
+ lea eax,objs
+ call A_SECPTR ; returns 'C' clear if hint field is valid
+ ENDIF
+ IFIDN <kind>,<ALBLK>
+ a = 1
+ mov eax,objs
+ call A_ALBLK
+ ENDIF
+ IFIDN <kind>,<ASREC>
+ a = 1
+ mov eax,objs
+ call A_AS
+ ENDIF
+ IFIDN <kind>,<HEAPNAM>
+ a = 1
+ mov eax,objs
+ call A_HEAPNAM
+ ENDIF
+ IFIDN <kind>,<DCHDR>
+ a = 1
+ mov edx,arg1
+ mov eax,objs
+ call A_DCHDR
+ ENDIF
+ IFIDN <kind>,<DIRBLK>
+ a = 1
+ mov eax,objs
+ call A_DIRBLK
+ ENDIF
+ IFIDN <kind>,<BUF>
+ a = 1
+ mov eax,objs
+ call A_BUF
+ ENDIF
+ IFIDN <kind>,<SBDIR>
+ a = 1
+ mov eax,objs
+ call A_SBDIR
+ ENDIF
+ IFIDN <kind>,<FNODE>
+ a = 1
+ mov eax,objs
+ call A_FNODE
+ ENDIF
+
+ IFE a
+ .error illegal option
+ ENDIF
+
+
+ IFB <nopush>
+ popfd
+ popad
+ nop ; errata
+ ENDIF
+ ENDM
+ELSE
+ ASSERT Macro a,b,c
+ ENDM
+ENDIF
+
+;** Heap sanity check macro (controlled by DEBUG flag)
+;
+; item - make sure this points to a heap allocated block
+; (return value from GHS or GHS_)
+; if blank, just the arena is checked.
+
+IFDEF DEBUG
+HeapChk Macro item
+ ifndef A_HEAP
+ extrn A_HEAP:near
+ endif
+ push edx
+ ifb <item>
+ mov edx, 0 ;; don't zap the flags
+ endif
+ ifdif <edx>, <item>
+ mov edx, item
+ endif
+ call A_HEAP
+ pop edx
+ENDM
+
+ELSE
+ HeapChk Macro item
+ ENDM
+ENDIF
+
+
+DPUBLIC MACRO arg
+ ifdef DEBUG
+ Public arg
+ endif
+ENDM
+
+
+BREAK MACRO subtitle
+ SUBTTL subtitle
+ PAGE
+ENDM
+
+;** CalcGBHShift - calculate the GBH shift factor
+
+GBHShift = 0
+
+CalcGBHShift MACRO
+ local ?tmp
+
+ if GBHShift NE 0
+ EXITM
+ endif
+
+ ?tmp = (SECSIZE*SPB) / (size BUFNODE)
+ rept 16
+ if ?tmp EQ 1
+ exitm
+ endif
+ ?tmp = ?tmp / 2
+ GBHShift = GBHShift + 1
+ endm
+
+ .errnz SECSIZE * SPB - ((size BUFNODE) SHL GBHShift)
+ENDM
+
+
+;** GBH - Get Buffer Header
+;
+; GBH takes the address of a buffer data area and returns the
+; address of it's header.
+;
+; Since the data area is linear in memory and the headers are linear,
+; we just do a simple linear mapping.
+;
+; GBH transforms the address in the register without modifying
+; any other registers.
+;
+; GBH reg
+
+GBH MACRO reg
+ CalcGBHShift
+ sub reg,Bufbase ; (reg) = offset in array of buffers
+ shr reg,GBHShift ; (reg) = offset in array of bufnotes
+
+; Get rid of low order stuff. Since reg may be an offset WITHIN
+; a buffer and not just a poitner to the header itself, we mask off the
+; low order stuff.
+
+ ifidn <reg>,<eax>
+ and al,100h - (SIZE bufnode)
+ else
+ ifidn <reg>,<ebx>
+ and bl,100h - (SIZE bufnode)
+ else
+ ifidn <reg>,<ecx>
+ and cl,100h - (SIZE bufnode)
+ else
+ %out add more code to this macro
+ .err
+ endif
+ endif
+ endif
+ add reg, OFFSET DS:Bhbase
+ ENDM
+
+;* RetHeap - Return Heap Item
+;
+; RetHeap address-of-item
+
+RetHeap MACRO reg
+ HeapChk reg
+ add dword ptr -4[reg],80000000h-4
+ ENDM
+
+
+;* GetPerm - Get Perminant Memory
+;
+; Returns a block of memory which will be perminantly
+; occupied
+
+GetPerm Macro reg,len
+ local l1,l2
+l1: mov reg,PermPtr
+ add PermPtr,len
+ cmp reg,PermLim
+ jb short l2
+ push len
+ call aapm ; allocate additional perm memory
+ jmp l1
+ align 4
+l2:
+ ENDM
+
+
+ BREAK <Double Chain Manipulation Macros>
+
+;** The following macros manipulate double-linked lists.
+;
+; All macros take as their first argument the offset to
+; the pointer pair.
+
+;** DCADDB - Add Item to Back of List
+;
+; DCADDB offset,listreg,itemreg,scrreg
+;
+; offset = offset into structure of links to edit
+; listreg = address of list head node
+; itemreg = address of item to insert
+; scrreg = scratch register to roach
+
+DCADDB MACRO o,LR,IR,SR
+ mov SR,o.BAK[LR]
+ mov o.FWD[SR],IR
+ mov o.FWD[IR],LR
+ mov o.BAK[IR],SR
+ mov o.BAK[LR],IR
+ ENDM
+
+
+;** DCADDF - Add Item to Front of List
+;
+; DCADDF offset,listreg,itemreg,scrreg
+;
+; offset = offset into structure of links to edit
+; listreg = address of list head node
+; itemreg = address of item to insert
+; scrreg = scratch register to roach
+
+DCADDF MACRO o,LR,IR,SR
+ mov SR,o.FWD[LR]
+ mov o.FWD[IR],SR
+ mov o.BAK[IR],LR
+ mov o.BAK[SR],IR
+ mov o.FWD[LR],IR
+ ENDM
+
+
+
+;** DCREM - Remove Item from Double Link Chain
+;
+; DCREM offset,adrreg,scrreg1,scrreg2
+;
+; offset = offset into structure of links to edit
+; adrreg = address of item to remove
+; scrreg? = two registers to scratch
+
+DCREM MACRO o,ir,r2,r3
+ mov r2,o.FWD[ir]
+ mov r3,o.BAK[ir]
+ mov o.BAK[r2],r3
+ mov o.FWD[r3],r2
+ ENDM
+
+
+;** DCMOVF - Move Item to the Front of the Chain
+;
+; DCMOVF offset,listreg,itemreg,scrreg,[scrreg2]
+;
+; offset = offset into structure of links to edit
+; listreg = address of list head node
+; itemreg = address of item to insert
+; scrreg = scratch register to roach
+; scrreg2 = optional additional register to roach
+;
+; BUGBUG - check users for supply of scratch registers
+
+DCMOVF MACRO o,lr,ir,sr,sr2
+ IFNB <sr2>
+ DCREM o,ir,sr,sr2
+ else
+ push lr
+ DCREM o,ir,lr,sr
+ pop lr
+ endif
+ DCADDF o,lr,ir,sr
+ ENDM
+
+
+;** DCMOVB - Move Item to the Back of the Chain
+;
+; DCMOVB offset,listreg,itemreg,scrreg
+;
+; offset = offset into structure of links to edit
+; listreg = address of list head node
+; itemreg = address of item to insert
+; scrreg = scratch register to roach
+
+DCMOVB MACRO o,lr,ir,sr
+ push lr
+ DCREM o,ir,lr,sr
+ pop lr
+ DCADDB o,lr,ir,sr
+ ENDM
+
+
+;** ADDHASH - add a buffer to hash list
+;
+; ADDHASH lsn,buf,sr1,sr2,sr3
+;
+; lsn = Vsector or Psector number of beginning of buffer
+; may be any of the arg registers
+; buf = address of buffer header
+; sr1 = scratch register
+; sr2 = 'nother scratch register
+; sr3 = last scratch register
+
+ADDHASH MACRO lsn,buf,sr1,sr2,sr3
+ local l1,l2
+
+ mov sr1,lsn
+ and sr1,(HASHCNT-1)*4 ; (sr1) = hash index
+ add sr1,offset DGROUP:HashTab
+ mov B_HTA[buf],sr1 ; save hash ptr for later use by DCADDF
+ mov sr2,[sr1]
+ifidn <sr2>,<ecx>
+ jecxz l1
+else
+ and sr2,sr2
+ jz short l1 ; nobody on list yet
+endif
+ DCADDF B_HASH,sr2,buf,sr3 ; add to hash list
+ jmp short l2
+
+ align 4
+l1: mov B_HASH.FWD[buf],buf ; empty list, make self-linked
+ mov B_HASH.BAK[buf],buf
+l2: mov [sr1],buf ; put our guy at front of chain
+ ENDM
+
+
+;** HASHFIND - find a sector in the hash
+;
+; HASHFIND lsn,buf,sr1,fnd
+;
+; lsn = logical sector number to find. HASHFIND presumes it
+; has already been rounded to a multiple of SPB
+; buf = register where buffer is returned
+; sr1 = scratch register
+; fnd = where to go if found
+; NOTE: falls through if not found
+
+
+HASHFIND MACRO lsn,buf,sr1,fnd
+ local l1,l2
+
+ mov sr1,lsn
+ and sr1,(HASHCNT-1)*4 ; (sr1) = hash index
+ mov buf,Hashtab[sr1]
+ifidn <buf>,<ecx>
+ jecxz l2
+else
+ and buf,buf
+ jz short l2 ; no entries in chain, block not there
+endif
+ mov sr1,buf ; save address of first guy
+
+; Run through circular chain, looking for a match.
+;
+; (buf) = next guy to check out
+; (lsn) = sector value to match
+; (sr1) = address of first guy in chain
+
+ align 4
+l1: cmp lsn,B_SEC[buf]
+ je fnd ; got him
+ mov buf,B_HASH.FWD[buf] ; go to next buffer
+ cmp buf,sr1 ; have we gone around yet?
+ jne l1 ; no, go examine buffer
+l2:
+ ENDM
+
+
+
+;** FALLTHRU - Verifies Fallthrough Validity
+
+FALLTHRU MACRO labl
+ align 4 ; don't have errnz fail due to alignment
+ IF2 ; of following label
+ .errnz labl-$
+ ENDIF
+ ENDM
+
+
+;** INTERR - Internal Error
+; INTERRnz - Internal error iff 'Z' clear
+; INTERRzr - Internal error iff 'Z' set
+; INTERRc - Internal error if 'C' set
+
+ifdef DEBUG
+INTERR MACRO
+ local l
+l: int 3
+ jmp l
+ ENDM
+
+INTERRzr MACRO
+ local l
+ jnz short l
+ int 3
+ jmp $-1
+l:
+ ENDM
+
+INTERRc MACRO
+ local l
+ jnc short l
+ int 3
+ jmp $-1
+l:
+ ENDM
+
+INTERRnz MACRO
+ local l
+ jz short l
+ int 3
+ jmp $-1
+l:
+ ENDM
+else
+INTERR MACRO
+ ENDM
+INTERRzr MACRO
+ ENDM
+INTERRc MACRO
+ ENDM
+INTERRnz MACRO
+ ENDM
+endif
+
+;* Debug Traps
+;
+; These are removed as the code is exercised
+
+TRAPC macro
+ local l
+ jnc short l
+ int 3
+l:
+ ENDM
+
+TRAPZ macro
+ local l
+ jnz short l
+ int 3
+l:
+ ENDM
+
+TRAPNZ macro
+ local l
+ jz short l
+ int 3
+l:
+ ENDM
+
+
+;** PANIC - Panic File System
+;
+; BUGBUG - fix me to do something besides trap
+
+PANIC macro
+ local l
+l: int 3
+ jmp l
+ ENDM
+
+;** Bulk Register Save/Restore
+;
+
+SAVE MACRO reglist
+IRP reg,<reglist>
+ PUSH reg
+ENDM
+ENDM
+.xcref SAVE
+
+RESTORE MACRO reglist ;; pop those registers
+IRP reg,<reglist>
+ POP reg
+ENDM
+ENDM
+.xcref RESTORE
+
+
+;* ret16 - perform a 16bit return
+;
+; If we are in a use32 segment then we must put out an operand size
+; override before the ret.
+
+ret16 macro stkfix
+ ife @WordSize - 4
+ db 66h ;; operand size override
+ endif
+ retf stkfix
+ endm
+.xcref ret16
+
+
+;* call1616 - perform an indirect 16bit far call
+;
+; If we are in a use32 segment then we must put out an operand size
+; override before the call and then cast the target to "FWORD" so that
+; MASM will generate the correct instruction.
+;
+; The target must be indirect.
+
+call1616 macro target
+ .errnz (type target) - 4
+ ife @WordSize - 4
+ db 66h ;; operand size override
+ call fword ptr target ;; force indirect far call
+ else
+ call target
+ endif
+ endm
+.xcref call1616
+
+
+;** Dpush - Push 32-bit constant
+;
+; MASM has no way of expressing this in USE16 mode.
+
+DPUSH macro a
+ifdef USE32
+ push a
+else
+ push a ; low order
+ push 0
+endif
+ ENDM
+
+;** Push16 - generate a 16bit push in a 32-bit code segment. This is
+; needed when pushing segment regs and immediate values as arguments
+; to 16bit procedures.
+
+push16 macro operand
+ db 66h
+ push operand
+ endm
+
+
+;** STATINC - Do an INC if STAT gathering is enabled
+;
+; Preserves 'C'
+
+STATINC macro a
+ifdef STATS
+ inc a
+endif
+ ENDM
+
+;** STATDEC - Do an DEC if STAT gathering is enabled
+;
+; Preserves 'C'
+
+STATDEC macro a
+ifdef STATS
+ dec a
+endif
+ ENDM
+
+
+;** LogHCNT - Log OFT holding/unholding
+;
+
+ifdef DEBUG
+
+LOGHCNT MACRO reg
+ifndef DoLogHcnt
+ EXTRN DoLogHcnt:near
+endif
+ pushfd
+ push eax
+ mov eax,reg
+ call DoLogHcnt
+ pop eax
+ popfd
+ ENDM
+
+;** LogSCNT - Lock SBDIR holding/unholding
+;
+
+LOGSCNT MACRO REG
+ifndef DoLogScnt
+ EXTRN DoLogScnt:near
+endif
+ pushfd
+ push eax
+ifdif <REG>,<eax>
+ mov eax,reg
+endif
+ call DoLogScnt
+ pop eax
+ popfd
+ ENDM
+else
+LOGHCNT MACRO
+ ENDM
+LOGSCNT MACRO
+ ENDM
+endif
+
+ifdef DEBUG
+ CALLVBS MACRO
+ ifndef VBS
+ EXTRN VBS:NEAR
+ endif
+ call VBS
+ ENDM
+else
+ CALLVBS MACRO
+ ENDM
+endif
+
+;** cBUFZAP - Call DoZap iff debug mode set
+;
+
+cBUFZAP Macro
+ifdef DEBUG
+ifndef DoZap
+ EXTRN DoZap:near
+endif
+ call DoZap
+endif
+ endm
+
+
+;** Stack Frame Macros
+;
+; These macros are used to allow a stack frame to be setup by
+; simple PUSHES and yet guarantee that the pushes won't drift
+; out of sync with the frame declaration.
+
+LASTEL MACRO struc,elem
+ .errnz size struc - elem - size elem
+?frof = elem
+ ENDM
+
+NEXTEL MACRO elem
+ .errnz ?frof - elem - size elem
+?frof = elem
+ ENDM
+
+DUMYEL MACRO si
+?frof = ?frof - si
+ ENDM
+
+FIRSTEL MACRO elem
+ .errnz ?frof - size elem
+?frof = elem
+ .errnz elem
+ ENDM
+
+
+;** CHKSECNUM - Check Sector number
+;
+; CHKSECNUM reg
+;
+; Make sure that reg has a sector number in it without the high order
+; volume ID bits
+
+
+CHKSECNUM MACRO reg
+ local l1
+ifdef DEBUG
+ test reg,NOT SECMASK
+ jz l1
+ INTERR
+l1:
+endif
+ ENDM
diff --git a/private/ntos/boot/bootcode/hpfs/i386/makefile b/private/ntos/boot/bootcode/hpfs/i386/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/ntos/boot/bootcode/hpfs/i386/makefile
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT OS/2
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/ntos/boot/bootcode/hpfs/i386/misc.inc b/private/ntos/boot/bootcode/hpfs/i386/misc.inc
new file mode 100644
index 000000000..7135cf542
--- /dev/null
+++ b/private/ntos/boot/bootcode/hpfs/i386/misc.inc
@@ -0,0 +1,64 @@
+;static char *SCCSID = "@(#)misc.h 12.2 88/12/19";
+; #define DEBUG 1
+
+ifdef MASM
+
+ include filemode.inc
+
+ BREAK <Misc. Definitions>
+
+endif
+
+ERROR_OPLOCKED equ 0eeh
+
+
+;* MISC.INC - Miscelaneous structure definitions.
+;
+; These need to be included first because other structures
+; make use of them.
+;
+
+
+;* SecPtr - Sector Pointer Structure
+;
+; Structures which contain a sector number usually use the
+; SecPtr structure, which contains an advisory pointer. The
+; pointer points to a buffer header, which is *probably* the
+; header for the sector named in SecPtr, but the user must check.
+;
+
+SECPTR struc
+ SNUM dd ? ; VSector number
+ SHINT dw ? ; hint address, 0 if none
+SECPTR ends
+
+
+
+
+;* Write type flags for SDW
+;
+
+WT_CACH equ 01h ; write via cache
+WT_DIR equ 02h ; write direct as much as possible
+WT_EXT equ 04h ; write is extending the file
+
+
+;* Bit Map Sets
+
+BITMAPL equ -4 ; bit map length preceeds table
+BITMAPC equ -8 ; count of sectors left in bitmap
+
+
+;* conditional short value
+
+ifdef MASM
+ifdef USE16
+SHRT EQU < >
+else
+ifdef DEBUG
+SHRT EQU < >
+else
+SHRT EQU <short>
+endif
+endif
+endif
diff --git a/private/ntos/boot/bootcode/hpfs/i386/pinboot.asm b/private/ntos/boot/bootcode/hpfs/i386/pinboot.asm
new file mode 100644
index 000000000..412280f14
--- /dev/null
+++ b/private/ntos/boot/bootcode/hpfs/i386/pinboot.asm
@@ -0,0 +1,727 @@
+ page ,132
+ title pinboot - Pinball boot loader
+ name pinboot
+
+; The ROM in the IBM PC starts the boot process by performing a hardware
+; initialization and a verification of all external devices. If all goes
+; well, it will then load from the boot drive the sector from track 0, head 0,
+; sector 1. This sector is placed at physical address 07C00h.
+;
+; The boot code's sole resposiblity is to find NTLDR, load it at
+; address 2000:0000, and then jump to it.
+;
+; The boot code understands the structure of the Pinball root directory,
+; and is capable of reading files. There is no contiguity restriction.
+;
+; The boot sector does not understand the Pinball file system's hotfixing --
+; there isn't enough room. So if NTLDR is hotfixed, we're out of luck.
+;
+
+MASM equ 1
+ .xlist
+ .286
+ include macro.inc
+;
+A_DEFINED equ 1 ; don't "extrn" A_xxxx functions
+
+ .386
+ include const.inc ;get the file system's headers.
+ include chain.inc
+ include misc.inc
+ include fnode.inc
+ include dir.inc
+ include superb.inc
+ .286
+ .list
+
+DoubleWord struc
+lsw dw ?
+msw dw ?
+DoubleWord ends
+
+;
+; The following are various segments used by the boot loader. The first
+; two are the segments where the boot sector is initially loaded and where
+; the boot sector is relocated to. The others are the static locations
+; where the mini-FSD and OS2KRNL are loaded. There is no segment definition
+; for where OS2LDR is loaded, since its position is variable (it comes right
+; after the end of OS2KRNL).
+;
+
+BootSeg segment at 07c0h ; this is where the ROM loads us initially.
+BootSeg ends
+
+NewSeg segment at 0d00h ; this is where we'll relocate to.
+NewSeg ends ; enough for 16 boot sectors +
+ ; 4-sector scratch
+ ; below where we'll load OS2KRNL.
+
+LdrSeg segment at 2000h ; we want to load the loader at 2000:0000
+LdrSeg ends
+
+ScrOfs equ 0f800h - 0d000h ; offset of 2K scratch area.
+
+MOVEDD macro dest, src ; macro to copy a doubleword memory variable.
+ mov ax, src.lsw
+ mov dest.lsw, ax
+ mov ax, src.msw
+ mov dest.msw, ax
+ ENDM
+
+;/********************** START OF SPECIFICATIONS ************************/
+;/* */
+;/* SUBROUTINE NAME: pinboot */
+;/* */
+;/* DESCRIPTIVE NAME: Bootstrap loader */
+;/* */
+;/* FUNCTION: To load NTLDR into memory. */
+;/* */
+;/* NOTES: pinboot is loaded by the ROM BIOS (Int 19H) at */
+;/* physical memory location 0000:7C00H. */
+;/* pinboot runs in real mode. */
+;/* This boot record is for Pinball file systems only. */
+;/* Allocation information for NTLDR may not */
+;/* exceed an FNODE. */
+;/* */
+;/* ENTRY POINT: pinboot */
+;/* LINKAGE: Jump (far) from Int 19H */
+;/* */
+;/* INPUT: CS:IP = 0000:7C00H */
+;/* SS:SP = 0030:00FAH (CBIOS dependent) */
+;/* */
+;/* EXIT-NORMAL: */
+;/* DL = INT 13 drive number we booted from */
+;/* Jmp to main in OS2LDR */
+;/* */
+;/* EXIT-ERROR: None */
+;/* */
+;/* EFFECTS: Pinball mini-FSD is loaded into the physical */
+;/* memory location 000007C0H */
+;/* NTLDR is loaded into the physical memory */
+;/* location 00020000H */
+;/* */
+;/* MESSAGES: */
+;/* A disk read error occurred. */
+;/* The file NTLDR cannot be found. */
+;/* Insert a system diskette and restart the system. */
+;/* */
+;/*********************** END OF SPECIFICATIONS *************************/
+BootCode segment ;would like to use BootSeg here, but LINK flips its lid
+ assume cs:BootCode,ds:nothing,es:nothing,ss:nothing
+
+ org 0 ; start at beginning of segment, not 0100h.
+
+ public _pinboot
+_pinboot proc far
+ jmp start
+;
+; The following is the default BPB for Pinball hard disks. It may
+; be modified by FORMAT or SYS before being installed on the disk.
+;
+; Parameters such as Heads, SectorsPerTrack, and SectorsLong are
+; set up for a 20MB hard disk, so that a binary image of this boot
+; record may be written directly to a test hard disk without having
+; to reformat the drive.
+;
+; Note that this is really just a place-holder--anyone who writes
+; the boot code should preserve the volume's existing BPB.
+;
+Version db "IBM 10.2"
+BPB label byte
+BytesPerSector dw SECSIZE ; Size of a physical sector
+SectorsPerCluster db 4 ; Sectors per allocation unit
+ReservedSectors dw 1 ; Number of reserved sectors
+Fats db 2 ; Number of fats
+DirectoryEntries dw 0200h ; Number of directory entries
+Sectors dw 0 ; No. of sectors - no. of hidden sectors
+Media db 0f8h ; Media byte
+FatSectors dw 0029h ; Number of fat sectors
+SectorsPerTrack dw 17 ; Sectors per track
+Heads dw 4 ; Number of surfaces
+HiddenSectors dd 0011h ; Number of hidden sectors
+SectorsLong dd 0a2c3h ; Number of sectors iff Sectors = 0
+;
+; The following is the rest of the Extended BPB for the volume.
+; The position and order of DriveNumber and CurrentHead are especially
+; important, since those two variables are loaded into a single 16-bit
+; register for the BIOS with one instruction.
+;
+DriveNumber db 80h ; Physical drive number (0 or 80h)
+CurrentHead db ? ; Variable to store current head number
+
+Signature db 28h ; Signature Byte for bootsector
+BootID dd 64d59c15h ; Boot ID field.
+Boot_Vol_Label db 'C-DRIVE',0,0,0,0 ;volume label.
+Boot_System_ID db 'HPFS ' ; Identifies the IFS that owns the vol.
+;
+; The following variables are not part of the Extended BPB; they're just
+; scratch variables for the boot code.
+;
+SectorBase dd ? ; next sector to read
+CurrentTrack dw ? ; current track
+CurrentSector db ? ; current sector
+SectorCount dw ? ; number of sectors to read
+lsnSaveChild dd ? ; sector to continue directory search
+
+;****************************************************************************
+start:
+;
+; First of all, set up the segments we need (stack and data).
+;
+ cli
+ xor ax, ax ; Set up the stack to just before
+ mov ss, ax ; this code. It'll be moved after
+ mov sp, 7c00h ; we relocate.
+ sti
+
+ mov ax, Bootseg ; Address our BPB with DS.
+ mov ds, ax
+ assume ds:BootCode
+;
+; Now read the 16-sector boot block into memory. Then jump to that
+; new version of the boot block, starting in the second sector
+; (after the bootrecord sig).
+;
+ mov SectorBase.lsw, 0 ; read sector zero.
+ mov SectorBase.msw, 0
+ mov word ptr [SectorCount], SEC_SUPERB+4 ; read boot/superblock.
+ mov ax, NewSeg ; read it at NewSeg.
+ mov es, ax
+ sub bx, bx ; at NewSeg:0000.
+ call DoReadLL ; Call low-level DoRead routine
+;
+ push NewSeg ; we'll jump to NewSeg:0200h.
+ push offset mainboot ; (the second sector).
+ ret ; "return" to the second sector.
+_pinboot endp
+
+;*******************************************************************************
+;
+; Low-level read routine that doesn't work across a 64k addr boundary.
+;
+; Read SectorCount sectors (starting at SectorBase) to es:bx.
+;
+; As a side effect, SectorBase is updated (but es:bx are not)
+; and SectorCount is reduced to zero.
+;
+DoReadLL proc
+ push ax ; save important registers
+ push bx
+ push cx
+ push dx
+ push es
+
+DoRead$Loop:
+ mov ax, SectorBase.lsw ; (DX:AX) = start sector of next track
+ mov dx, SectorBase.msw
+ add ax, HiddenSectors.lsw ; adjust for partition's base sector
+ adc dx, HiddenSectors.msw
+ div SectorsPerTrack ; (DX) = sector within track, (AX)=track
+ inc dl ; sector numbers are 1-based, not 0
+ mov CurrentSector, dl
+ xor dx, dx ; prepare for 32-bit divide
+ div Heads ; (DX) = head no., (AX) = cylinder
+ mov CurrentHead, dl
+ mov CurrentTrack, ax
+
+; CurrentHead is the head for this next disk request
+; CurrentTrack is the track for this next request
+; CurrentSector is the beginning sector number for this request
+;
+; Compute the number of sectors that we may be able to read in a single ROM
+; request.
+;
+ mov ax, SectorsPerTrack ; could read up to this much
+ sub al, CurrentSector ; offset within this track
+ inc ax ; CurrentSector was 1-based
+;
+; AX is the number of sectors that we may read.
+;
+ cmp ax, SectorCount ; do we need to read whole trk?
+ jbe DoRead$FullTrack ; yes we do.
+ mov ax, SectorCount ; no, read a partial track.
+;
+; AX is now the number of sectors that we SHOULD read.
+;
+DoRead$FullTrack:
+ push ax ; save sector count for later calc.
+ mov ah, 2 ; "read sectors"
+ mov dx, CurrentTrack ; at this cylinder
+ mov cl, 6
+ shl dh, cl ; high 2 bits of DH = bits 8,9 of DX
+ or dh, CurrentSector ; (DH)=cyl bits | 6-bit sector no.
+ mov cx, dx ; (CX)=cylinder/sector no. combination
+ xchg ch, cl ; in the right order
+ mov dx, word ptr DriveNumber ; drive to read from, head no.
+ int 13h ; call BIOS.
+
+ pop ax
+ jb BootErr$he ; If errors report
+ add SectorBase.lsw, ax ; increment logical sector position
+ adc SectorBase.msw, 0
+ sub SectorCount, ax ; exhausted entire sector run?
+ jbe DoRead$Exit ; yes, we're all done.
+ shl ax, 9 - 4 ; (AX)=paragraphs read from last track
+ mov dx, es ; (DX)=segment we last read at
+ add dx, ax ; (DX)=segment right after last read
+ mov es, dx ; (ES)=segment to read next track at
+ jmp DoRead$Loop
+;
+DoRead$Exit:
+ pop es
+ pop dx
+ pop cx
+ pop bx
+ pop ax
+ ret
+
+DoReadLL endp
+
+;****************************************************************************
+;
+; BootErr - print error message and hang the system.
+;
+BootErr proc
+BootErr$fnf:
+ mov si,offset TXT_MSG_SYSINIT_FILE_NOT_FD +2
+ jmp short BootErr2
+BootErr$he:
+ mov si,offset TXT_MSG_SYSINIT_BOOT_ERROR +2
+BootErr2:
+ call BootErr$print
+ mov si,offset TXT_MSG_SYSINIT_INSER_DK +2
+ call BootErr$print
+ sti
+ jmp $ ;Wait forever
+BootErr$print:
+ lodsb ; Get next character
+ cmp al, 0
+ je BootErr$Done
+ mov ah,14 ; Write teletype
+ mov bx,7 ; Attribute
+ int 10h ; Print it
+ jmp BootErr$print
+BootErr$Done:
+ ret
+BootErr endp
+
+;****************************************************************************
+ include pinboot.inc ;suck in the message text
+;
+; Names of the files we look for. Each consists of a length byte
+; followed by the filename as it should appear in a directory entry.
+;
+ntldr db 5, "NTLDR"
+
+
+ReservedForFuture DB 22 dup(?) ;reserve remaining bytes to prevent NLS
+ ;messages from using them
+
+ .errnz ($-_pinboot) GT (SECSIZE-2),<FATAL PROBLEM: first sector is too large>
+
+ org SECSIZE-2
+ db 55h,0aah
+
+;****************************************************************************
+;
+; mainboot -
+;
+mainboot proc far
+ mov ax, cs ; get the new DS.
+ mov ds, ax
+ add ax, ((SEC_SUPERB + 4) * SECSIZE) / 16 ; address of scratch.
+ mov es, ax
+ mov ax, ds ; get DS again.
+ shl ax, 4 ; convert to an offset.
+ cli
+ mov sp, ax ; load new stack, just before boot code.
+ sti
+;
+; First find the root FNODE on disk and read it in.
+;
+ mov bx, SEC_SUPERB * SECSIZE + SB_ROOT
+ MOVEDD SectorBase, [bx] ; SectorBase = sblk.SB_ROOT.
+ mov SectorCount, 1 ; it's one sector long.
+ sub bx, bx ; read at scratch segment:0.
+ call DoRead
+;
+; Now find the root DIRBLK on disk and save its address.
+;
+ MOVEDD RootDB, es:[bx].FN_ALREC.AL_POF ; RootDB = f.FN_ALREC.AL_POF.
+;
+; Load NTLDR at 20000h.
+;
+ mov si, offset ntldr ; point to name of NTLDR.
+ MOVEDD SectorBase, RootDB ; start at root dirblk
+ call FindFile
+ mov ax, LdrSeg ; load at this segment.
+ call LoadFile ; find it and load it.
+;
+; We've loaded NTLDR--jump to it. Jump to NTLDR. Note that NTLDR's segment
+; address was stored on the stack above, so all we need to push is the offset.
+;
+; Before we go to NTLDR, set up the registers the way it wants them:
+; DL = INT 13 drive number we booted from
+;
+
+ mov dl, DriveNumber
+ mov ax,1000
+ mov es, ax ; we don't really need this
+ lea si, BPB
+ sub ax,ax
+ push LdrSeg
+ push ax
+ ret ; "return" to OS2LDR.
+mainboot endp
+
+;****************************************************************************
+;
+; DoRead - read SectorCount sectors into ES:BX starting from sector
+; SectorBase.
+;
+; NOTE: This code WILL NOT WORK if ES:BX does not point to an address whose
+; physical address (ES * 16 + BX) MOD 512 != 0.
+;
+; DoRead adds to ES rather than BX in the main loop so that runs longer than
+; 64K can be read with a single call to DoRead.
+;
+; Note that DoRead (unlike DoReadLL) saves and restores SectorCount
+; and SectorBase
+;
+DoRead proc
+ push ax ; save important registers
+ push bx
+ push cx
+ push dx
+ push es
+ push SectorCount ; save state variables too
+ push SectorBase.lsw
+ push SectorBase.msw
+;
+; Calculate how much we can read into what's left of the current 64k
+; physical address block, and read it.
+;
+;
+ mov ax,bx
+
+ shr ax,4
+ mov cx,es
+ add ax,cx ; ax = paragraph addr
+
+;
+; Now calc maximum number of paragraphs that we can read safely:
+; 4k - ( ax mod 4k )
+;
+
+ and ax,0fffh
+ sub ax,1000h
+ neg ax
+
+;
+; Calc CX = number of paragraphs to be read
+;
+ mov cx,SectorCount ; convert SectorCount to paragraph cnt
+ shl cx,9-4
+
+DoRead$Loop64:
+ push cx ; save cpRead
+
+ cmp ax,cx ; ax = min(cpReadSafely, cpRead)
+ jbe @F
+ mov ax,cx
+@@:
+ push ax
+;
+; Calculate new SectorCount from amount we can read
+;
+ shr ax,9-4
+ mov SectorCount,ax
+
+ call DoReadLL
+
+ pop ax ; ax = cpActuallyRead
+ pop cx ; cx = cpRead
+
+ sub cx,ax ; Any more to read?
+ jbe DoRead$Exit64 ; Nope.
+;
+; Adjust ES:BX by amount read
+;
+ mov dx,es
+ add dx,ax
+ mov es,dx
+;
+; Since we're now reading on a 64k byte boundary, cpReadSafely == 4k.
+;
+ mov ax,01000h ; 16k paragraphs per 64k segment
+ jmp short DoRead$Loop64 ; and go read some more.
+
+DoRead$Exit64:
+ pop SectorBase.msw ; restore all this crap
+ pop SectorBase.lsw
+ pop SectorCount
+ pop es
+ pop dx
+ pop cx
+ pop bx
+ pop ax
+ ret
+DoRead endp
+;****************************************************************************
+;
+; ReadScratch - reads a block of 4 sectors into the scratch area.
+;
+; ENTRY: SectorBase = LSN to read.
+;
+; EXIT: 4 sectors at AX read at BootSeg:ScrOfs
+;
+; USES: all
+;
+ReadScratch proc near
+ push es
+ push bx
+ mov word ptr SectorCount, 4 ; read 4 sectors.
+ push ds ; address scratch area.
+ pop es
+ mov bx, ScrOfs ; with ES:BX.
+ call DoRead
+ pop bx
+ pop es
+ ret
+ReadScratch endp
+;****************************************************************************
+;
+; FindFile - finds a file in the root directory
+;
+; ENTRY: DS:SI -> name of file to find.
+; SectorBase = LSN of first DirBlk to read
+;
+; EXIT: ES:BX -> dirent of file
+; SectorBase = lsn of current DirBlk (for next directory search)
+;
+; USES: all
+;
+FindFile proc near
+ push ds
+ pop es ; address data with ES too.
+ call ReadScratch ; read DirBlk (SectorBase already set)
+ sub cx, cx ; prepare to store name length.
+ mov cl, [si] ; fetch the length byte.
+ inc si ; and skip to the name.
+ mov dx, cx ; save a copy of it.
+
+ff1: mov bx, DB_START + ScrOfs ; point to first DIRENT, in scratch.
+ jmp short ff12
+;
+; bx -> last entry examined
+; cx = length of the name we're looking for
+; si -> name we're looking for, without the count byte ("search name")
+;
+ff10: add bx, [bx].DIR_ELEN ; move to next entry.
+ call UpcaseName
+
+ff12: mov ax, si ; save search name address.
+ mov cx, dx ; reload search name length.
+ lea di, [bx].DIR_NAMA ; point to current DIRENT name.
+ repe cmpsb ; compare bytes while equal.
+ mov si, ax ; restore search name address.
+ jne ff20 ; not equal, search on
+;
+; Looks like the names match, as far as we compared them. But if
+; the current name was longer than the search name, we didn't compare
+; them completely. Check the lengths.
+;
+ cmp dl, [bx].DIR_NAML
+ jne ff20 ; not equal, try downpointer if any
+
+ ret ; equal - Found the file
+
+
+; Names don't match. If the current entry has a downpointer,
+; search it.
+;
+ff20: test byte ptr [bx].DIR_FLAG, DF_BTP
+ jz ff30 ; no downpointer, check for end
+
+; Follow the DownPointer.
+; Load the child DIRBLK and search it.
+;
+ add bx, [bx].DIR_ELEN ; move to next entry.
+ MOVEDD SectorBase, [bx-4] ; fetch last 4 bytes of prev entry.
+ call ReadScratch ; read child DIRBLK
+ jmp short ff1 ; search this dirblk
+
+;
+; We don't have a downpointer.
+; If this is the end entry in the dirblk, then we have to go up to the parent,
+; if any.
+
+ff30: test byte ptr [bx].DIR_FLAG, DF_END
+ jz ff10 ; not end of dirblk - check next DirEnt
+;
+; Check to see if we have a parent (not the top block). If so, read
+; the parent dirblk and find the downpointer that matches the current
+; sector. Then continue searching after that point.
+;
+ mov bx, ScrOfs ; point to dirblk header
+ test byte ptr [bx].DB_CCNT, 1 ; 1 means top block
+ jz ff40 ; not top, continue with parent
+ jmp FileNotFound ; top block - not found
+
+;
+; read in parent dirblk and find the dirent with this downpointer -
+; then continue after that point
+;
+ff40: MOVEDD lsnSaveChild, SectorBase ; save this sector number
+ MOVEDD SectorBase, [bx].DB_PAR
+ call ReadScratch ; read the parent
+
+ mov bx, DB_START + ScrOfs ; start at first entry of child
+ jmp short ff44
+
+; find our current downpointer
+
+ff42: add bx, di ; move to the next dirent
+
+ff44: mov di, [bx].DIR_ELEN ; downptr is 4 bytes from end of dirent
+ mov ax, [bx+di-4].lsw
+ cmp ax, lsnSaveChild.lsw ; compare low 2 bytes
+ jne ff42 ; not equal, try next DirEnt
+ mov ax, [bx+di-4].msw
+ cmp ax, lsnSaveChild.msw ; compare high 2 bytes
+ jne ff42 ; not equal, try next DirEnt
+
+ jmp ff30 ; continue from here
+
+FindFile endp
+;****************************************************************************
+;
+; LoadFile - reads file in at the specified segment.
+;
+; ENTRY: ES:BX -> fnode of file to load
+; AX = segment address to load at.
+;
+; USES: all
+;
+LoadFile proc near
+ push ax ; save segment to load at.
+;
+; Here, we have found the file we want to read. Fetch relevant info
+; out of the DIRENT: the file's FNODE number and its size in bytes.
+;
+ sub bp, bp ; a zero register is handy.
+ MOVEDD FileSize, [bx].DIR_SIZE ; get file size
+ MOVEDD SectorBase, [bx].DIR_FN ; prepare to read FNODE
+ call ReadScratch ; read in the FNODE
+;
+ pop es ; restore segment to read at.
+ mov si, ScrOfs + FN_ALREC ; address the FNODE's array.
+ mov bx, ScrOfs + FN_AB ; address the FNODE's ALBLK.
+
+lf_go:
+ test byte ptr [bx].AB_FLAG, ABF_NODE ; are records nodes?
+ jnz lf_donode ; yes, go get a child.
+;
+; Here, we have a leaf block. Loop through the ALLEAF records,
+; reading each one's data run.
+;
+ mov cl, [bx].AB_OCNT ; get count of leaf records.
+ mov ch, 0 ; zero-extend.
+lf_loop:
+ MOVEDD SectorBase, [si].AL_POF ; load run start.
+ mov ax, word ptr [si].AL_LEN ; load run length.
+ mov SectorCount, ax
+ push bx ; save ALBLK pointer.
+ sub bx, bx ; read at ES:0000.
+ call DoRead
+ pop bx ; restore ALBLK pointer.
+ mov ax, es ; get segment we just used
+ shl SectorCount, 9 - 4 ; cvt sectors to paragraphs
+ add ax, SectorCount ; get new segment address
+ mov es, ax ; store new segadr in ES
+ add si, size ALLEAF ; point to next leaf
+ loop lf_loop ; go get another run
+;
+; Here, we've exhausted an array of records. If we exhausted the
+; FNODE, we're done. Otherwise, we re-read our parent block, restore
+; where we were in it, and advance to the next record.
+;
+lf_blockdone:
+ cmp word ptr ds:[ScrOfs+FN_SIG+2], FNSIGVAL shr 16 ; in FNODE?
+ je lf_alldone ; yes, we've read the whole file.
+ MOVEDD SectorBase, ds:[ScrOfs+AS_RENT] ; fetch parent sector pointer.
+ call ReadScratch ; read in our parent.
+ pop si ; restore where we left off.
+ pop bx ; restore ALBLK pointer.
+ add si, size ALNODE ; move to next node.
+;
+; Here the block contains downpointers. Read in the next child
+; block and process it as a node or leaf block, saving where we were
+; in the current block.
+;
+lf_donode:
+ mov al, [bx].AB_OCNT ; get number of records.
+ mov ah, 0 ; zero-extend.
+ shl ax, 3 ; (AX)=size of array.
+ add ax, bx
+ add ax, size ALBLK ; (AX)->after end of array.
+ cmp si, ax ; are we done?
+ jae lf_blockdone ; yes, we've exhausted this blk.
+ push bx ; save ALBLK offset.
+ push si ; save current record offset.
+ MOVEDD SectorBase, [si].AN_SEC ; get child downpointer.
+ call ReadScratch ; read the child ALSEC.
+ mov si, size ALSEC + ScrOfs ; address the ALSEC's array.
+ mov bx, AS_ALBLK + ScrOfs ; address the ALSEC's ALBLK.
+ jmp short lf_go
+;
+; All done, return to caller.
+;
+lf_alldone:
+ ret
+LoadFile endp
+
+;****************************************************************************
+;
+; UpcaseName - Converts the name of the file to all upper-case
+;
+; ENTRY: ES:BX -> dirent of file
+;
+; USES: CX, DI
+;
+UpcaseName proc near
+ mov cl,[bx].DIR_NAML
+ xor ch,ch ; (cx) = # of bytes in name
+ lea di, [bx].DIR_NAMA ; (es:di) = pointer to start of name
+UN10:
+ cmp byte ptr es:[di], 'Z' ; Is letter lowercase?
+ jbe UN20
+
+ sub byte ptr es:[di], 'a'-'A' ; Yes, convert to uppercase
+UN20:
+ inc di
+ loop UN10
+
+ ret
+UpcaseName endp
+
+FileNotFound:
+ jmp BootErr$fnf
+
+;******************************************************************************
+RootDB dd ? ; LSN of root DIRBLK.
+
+Flag db ? ; used to store AB_FLAG.
+
+AllocInfo db size ALLEAF * ALCNT dup (0) ; copy of FNODE alloc info.
+
+FileSize dd ? ; size of file that was read.
+
+
+ .errnz ($-_pinboot) GT (SEC_SUPERB*SECSIZE),<FATAL PROBLEM: main boot record exceeds available space>
+
+ org SEC_SUPERB*SECSIZE
+
+BootCode ends
+
+ end _pinboot
diff --git a/private/ntos/boot/bootcode/hpfs/i386/sources b/private/ntos/boot/bootcode/hpfs/i386/sources
new file mode 100644
index 000000000..e877d5d35
--- /dev/null
+++ b/private/ntos/boot/bootcode/hpfs/i386/sources
@@ -0,0 +1,38 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ sources.
+
+Abstract:
+
+ This file specifies the target component being built and the list of
+ sources files needed to build that component. Also specifies optional
+ compiler switches and libraries that are unique for the component being
+ built.
+
+
+Author:
+
+ Steve Wood (stevewo) 12-Apr-1990
+
+NOTE: Commented description of this file is in \nt\bak\bin\sources.tpl
+
+!ENDIF
+
+MAJORCOMP=utils
+MINORCOMP=pinboot
+
+TARGETNAME=pinboot
+TARGETPATH=obj
+TARGETTYPE=LIBRARY
+
+SOURCES=pinboot.asm
+
+INCLUDES=\nt\public\sdk\inc
+C_DEFINES=-DDBG -DMEMLEAK -DCONDITION_HANDLING=1 -DNOMINMAX
+UMLIBS=obj\*\chkdsk.lib
+
+UMTYPE=console
diff --git a/private/ntos/boot/bootcode/hpfs/i386/superb.inc b/private/ntos/boot/bootcode/hpfs/i386/superb.inc
new file mode 100644
index 000000000..e670b800b
--- /dev/null
+++ b/private/ntos/boot/bootcode/hpfs/i386/superb.inc
@@ -0,0 +1,242 @@
+;** SUPERB.H - Super Block and Spare Block definitions
+;
+; FILESYS
+; Gregory A. Jones
+; Copyright 1988 Microsoft Corporation
+;
+; Modification history:
+; P.A. Williams 06/01/89 Added fields SPB_CPSEC and SPB_CPCNT to
+; the spare block.
+; P.A. Williams 06/05/89 Changed base and functional version no. to 1.
+;
+
+SEC_SUPERB equ 16 ; superblock is after 8K boot block
+SEC_SPAREB equ 17 ; spareblock is after superblock
+SEC_BOOT equ 0 ; boot sector
+
+
+;* SUPERB.INC - Super Block Definition
+;
+; The Superblock is the first block of the file system.
+; It starts at sector #4, leaving 2K for boot sectors.
+;
+; Pointer to the root directory
+; Pointer to the bit map
+; Clean pointer
+; Pointer to the bad list
+;
+
+RSP struc
+ P dd ? ; main psector pointer
+ P2 dd ? ; spare pointer
+RSP ends
+
+
+SuperB struc
+ SB_SIG1 dd ? ; signature value 1
+ SB_SIG2 dd ? ; signature value 2
+
+ SB_VER db ? ; version # of filesystem structures
+ SB_FVER db ? ; functional version number - the smallest/
+ ; oldest version of the filesystem that can
+ ; understand this disk - some version
+ ; enhancements may define fields which can be
+ ; ignored by earlier versions
+
+ SB_DUMY dw ? ; free
+
+ SB_ROOT dd ? ; Psector # of root fnode
+
+ SB_SEC dd ? ; # of sectors on volume
+ SB_BSEC dd ? ; # of bad sectors on volume
+
+ SB_BII db (size RSP) dup (?) ; Bitmap Indirect Block
+ SB_BBL db (size RSP) dup (?) ; badblock list chain #1
+
+ SB_CDDAT dd ? ; date of last CHKDSK
+ SB_DODAT dd ? ; date of last Disk Optimize
+
+ SB_DBSIZE dd ? ; # of sectors in dirblk band
+ SB_DBLOW dd ? ; first Psector in DIRBLK band
+ SB_DBHIGH dd ? ; last Psector in DIRBLK band
+ SB_DBMAP dd ? ; first Psector of DIRBLK band bit map. Starts
+ ; on a 2K boundary, 2K bytes maximum
+
+ SB_VOLNAME db 32 dup (?) ; Volume name
+
+ SB_SIDSEC dd ? ; sector # of first sector in SIDTAB
+ ; ID map is 4K - 8 contiguous sectors
+
+ SB_FILL db 512-100 dup (?) ; fill definition out to 512 bytes
+ ; MUST BE ZERO
+
+SuperB ends
+
+
+
+;* SpareB - Spare Block Definitions
+;
+; SpareB contains various emergency supplies and fixup information.
+; This stuff isn't in the superblock in order for the superblock
+; to be read only and decrease the liklihood that a flakey write
+; will cause the superblock to become unreadable.
+;
+; This sector is located directly after the superblock - sector 5.
+;
+; Note that the number of spare DIRBLKs is a format option, given
+; that they all have to fit into the SpareB, giving us a max of
+; 101 of them.
+;
+; Access to the SpareB is complicated by the fact that we can't
+; access it via the cache, since the cache may be unavailable.
+; If every cache buffer is dirty, we could get a HotFix error when
+; writing the first one, which would deadlock us if we needed to
+; read this stuff via the cache. Instead, we read it directly into
+; a private buffer via RdHF.
+;
+; This means that the disk layout must be such that each cache cluster
+; that contains the SpareB or the hotfix list must not contain any
+; other writable sector, to prevent us from having a modified
+; direct-written sector overwritten by an earlier unmodified copy
+; which was in a cache block. It's ok for the SuperB to be in the
+; same cache group as the SpareB since the SuperB is RO to the filesys.
+;
+; Checksums. Done on both Super Block and the Spare Block.
+; Both checksums are stored in the Spare Block. The checksum
+; field for the Super Block (SPB_SUPERBSUM) must be set when
+; calculating the checksum for the Spare Block. The checksum
+; field for the Spare Block (SPB_SPAREBSUM) must be zero when
+; calculating the checksum for the Spare Block.
+; If both checksum fields are zero, the checksums have not been
+; calculated for the volume.
+;
+
+SPAREDB equ 20 ; 20 spare DIRBLKs
+
+SpareB struc
+
+ SPB_SIG1 dd ? ; signature value 1
+ SPB_SIG2 dd ? ; signature value 2
+
+ SPB_FLAG db ? ; cleanliness flag
+ SPB_ALIGN db 3 dup (?) ; alignment
+
+ SPB_HFSEC dd ? ; first hotfix list P sector
+ SPB_HFUSE dd ? ; # of hot fixes in effect
+ SPB_HFMAX dd ? ; max size of hot fix list
+
+ SPB_SDBCNT dd ? ; # of spare dirblks
+ SPB_SDBMAX dd ? ; maximum number of spare DB values.
+ SPB_CPSEC dd ? ; code page sector
+ SPB_CPCNT dd ? ; number of code pages
+ SPB_SUPERBSUM dd ? ; Checksum of Super Block
+ SPB_SPAREBSUM dd ? ; Checksum of Spare Block
+ SPB_DUMY dd 15 dup (?) ; some extra space for future use
+ SPB_SPARDB dd 101 dup (?) ; Psector #s of spare dirblks
+SpareB ends
+
+
+; Super Block Signature
+
+SBSIG1 equ 0f995e849h ; two signatures cause we got lotsa
+SBSIG2 equ 0FA53E9C5h ; space
+SPSIG1 equ 0f9911849h ; two signatures cause we got lotsa
+SPSIG2 equ 0FA5229C5h ; space
+
+
+
+; Superblock Versions
+
+SBBASEV equ 2 ; base version
+SBBASEFV equ 2 ; base functional version
+
+; Spare Block Flags
+;
+
+SPF_DIRT equ 0001h ; file system is dirty
+SPF_SPARE equ 0002h ; spare DIRBLKs have been used
+SPF_HFUSED equ 0004h ; hot fix sectors have been used
+SPF_BADSEC equ 0008h ; bad sector, corrupt disk
+SPF_BADBM equ 0010h ; bad bitmap block
+SPF_VER equ 0080h ; file system was written by a version
+ ; < SB_VER, so some of the new fields
+ ; may have not been updated
+
+
+;* Bit maps
+;
+; PFS keeps track of free space in a series of bit maps.
+; Currently, each bit map is 2048 bytes, which covers about
+; 8 megabytes of disk space. We could rearrange these to be
+; more cylinder sensitive...
+;
+; The superblock has the address of a section of contiguous sectors
+; that contains a double word sector # for each bit map block. This
+; will be a maximum of 2048 bytes (4 sectors)
+;
+; Max # of size RAM (K) size 2nd lvl
+; bitmaps (meg) to reside bitmap
+; bitmap (bytes)
+;
+; 1 8.39 2 256
+; 2 16.78 4 512
+; 3 25.17 6 768
+; 4 33.55 8 1024
+; 5 41.94 10 1280
+; 6 50.33 12 1536
+; 7 58.72 14 1792
+; 8 67.11 16 2048
+; 9 75.50 18 2304
+; 10 83.89 20 2560
+; 15 125.83 30 3840
+; 20 167.77 40 5120
+; 30 251.66 60 7680
+; 40 335.54 80 10240
+; 50 419.43 100 12800
+; 100 838.86 200 25600
+; 200 1677.72 400 51200
+; 300 2516.58 600 76800
+; 400 3355.44 800 102400
+; 500 4194.30 1000 128000
+;
+
+
+
+;* Hot Fixing
+;
+; Each file system maintains a structure listing N "hot fix"
+; disk clusters of HOTFIXSIZ sectors each, each starting on
+; a multiple of HOTFIXSIZ. Whenever the file system discovers
+; that it's trying to write to a bad spot on the disk it will
+; instead select a free hot fix cluster and write there, instead.
+; The substitution will be recorded in the hot fix list, and the
+; SBF_SPARE bit will be set. The file system sill describes the
+; data as being in the bad old sectors; the disk interface will
+; do a mapping between the `believed' location and the true location.
+;
+; CHKDSK will be run as soon as possible; it will move the
+; hot fixed data from the hot fix cluster to somewhere else,
+; freeing that hot fix cluster, and adjusting the disk structure
+; to point to the new location of the data. As a result, entrys
+; on the hot fix list should be transient and few.
+;
+; The superblock contains the first sector of the hot fix list
+; which takes the following format:
+;
+; long oldsec[SB_HFMAX]; sector # of start of bad clusters
+; long newsec[SB_HFMAX]; sector # of start of subst. cluster
+; long fnode [SB_HFMAX]; fnode sector of file/directory
+; involved with bad cluster. May be
+; 0 (don't know) or invalid. The
+; repair program must verify that it
+; *is* an FNODE and must see if other
+; structures might also involve this
+; bad cluster.
+;
+; the SB_HFUSE field describes the number of these records which is
+; in use - unused ones should have oldsec[i] = 0. The list will
+; be 'dense' - no oldsec[i] will be 0 where i < SB_HFUSE.
+;
+; The sector(s) which contain the hot fix list must be contiguous
+; and may not themselves be defective.
+;
diff --git a/private/ntos/boot/bootcode/hpfs/i386/tables.inc b/private/ntos/boot/bootcode/hpfs/i386/tables.inc
new file mode 100644
index 000000000..07cf61244
--- /dev/null
+++ b/private/ntos/boot/bootcode/hpfs/i386/tables.inc
@@ -0,0 +1,201 @@
+;static char *SCCSID = "@(#)tables.h 12.2 88/12/19";
+ifdef MASM
+ BREAK <OFT - Open File Table>
+endif
+
+;* OFT - Open File Table
+;
+; The OFT contains file specific information which is independent
+; of an instance of use of the file.
+;
+; If the file is open for write access, we keep a pointer to
+; it's directory entry, not just it's
+; FNODE, so that we can update the length and modification time when it's
+; written.
+;
+; We store the directory's FNODE number and the file name, with these
+; we can find the directory entry again even if the directory has
+; been shuffled by creates or deletes of other files. Two advisorys
+; are kept - the Vsector number, cache block address, and cache block
+; offset of the actual directory entry. This information has three
+; levels of validity:
+;
+; 1) Vsector, header address, and offset are valid
+; you can find the dir entry easily
+; 2) the header address is invalid due to cache flushing.
+; Vsector # and offset are still valid, so read the
+; cache block and go directly to the entry
+; In this case the header address points to the wrong
+; Vsector
+; 3) the directory has been altered since we opened the file,
+; so none of this info is accurate. In this case the
+; directory alteration routines located this OFT
+; entry and zeroed the Vsector number. Go to the directory
+; and search the name again.
+;
+
+OFT struc
+ OFT_P db (size DCHDR) dup (?) ; double chain of OFT structures, rooted in OFTHead[i]
+ OFT_FHT db (size DCHDR) dup (?) ; double chain of FHT structures
+ OFT_RLCK db (size DCHDR) dup (?) ; double chain of RECLOCK structures
+ OFT_FN db (size SECPTR) dup (?) ; pointer to file FNODE
+ OFT_SBD dw ? ; pointer to SBDIR structure
+ OFT_DIRE db (size SECPTR) dup (?) ; pointer to directory block
+
+ OFT_CCNT dd ? ; DB_CCNT value for OFT_DIRE to check OFT_DIRO validity
+ OFT_FREEDCNT dd ? ; SD_FREEDCNT value for DIRE to be valid
+
+;
+; These length fields are used when writing the file.
+; The OFN_ entries will reflect the OFT_ALEN value. These
+; aren't updated in the FNODE until the file closes, whereup
+; they are trimmed back to OFT_LEN which is itself propigated
+; to the file's DIR entry. If write-through is set then the
+; OFN_ entries below will be propigated to the FNODE and
+; then to the disk, but if we crash the cleanup program
+; will deallocate the "extra" sectors.
+;
+
+ OFT_LEN dd ? ; file actual length
+ OFT_ALEN dd ? ; file allocated length (SECSIZE multiple)
+ OFT_WLEN dd ? ; last byte+1 of valid data in the file
+ ; (optimization for writing into extended areas
+ OFT_LAST dd ? ; Psector # of last sector in file, or 0
+ OFT_LRP db (size SECPTR) dup (?) ; last run pointer. Valid if OFT_LAST !=0
+ ; if OFN_AB.ABF_NODE ==0 this is the address of
+ ; an OFN_SEC record in this OFT
+ ; else this is a SECPTR to the SIB
+ ; containing the last run record
+
+ OFT_VOL dd ? ; pointer to VOLTAB for this guy
+
+ OFT_NAME dd ? ; address of name string len byte
+ ; followed by name string itself
+ ; len doesn't include len byte
+
+ OFT_DIRO dw ? ; offset into directory block for entry
+ OFT_FILL dw ? ; unused, fill
+
+ OFT_LCKCNT dw ? ; count of guys in OFT_RLCK
+
+ OFT_WCNT dw ? ; # of threads blocked on this OFT
+
+ ; the following three fields are used to
+ ; control access. They're identical in use
+ ; to the equivalent fields in SBDIR. The
+ ; Flag byte only contains locking/holding
+ ; flags, so if DWORD PTR OFT_HCNT is 0 then
+ ; the OFT is known to be free and clear
+
+ OFT_HCNT dw ? ; held count, has OTF_PND bit also
+ OFT_DMY db ? ; unused, must be 0
+ OFT_FLAG db ? ; flag byte, high order in OFT_HCNT dword
+
+ OFT_WAITC dd ? ; head of wait chain if locked
+
+ OFT_OPLOCK dd ? ; Oplock value, 0 if none
+
+ OFT_BANDP dd ? ; pointer to BandTab structure in BandList
+ ; for our last allocation. =0 if unused
+
+; The following 5 fields hold the accumulation of all FHTs for this OFT.
+; This saves us from having to scan the FHTs to do a sharing check upon
+; open. An OFT is unused when OFT_RD and OFT_WT and OFT_FIND are zero
+
+ OFT_RD dw ? ; # of opens for read
+ OFT_WT dw ? ; # of opens for write
+ OFT_DR dw ? ; # of opens with deny read
+ OFT_DW dw ? ; # of opens with deny write
+ OFT_COMPAT dw ? ; # of opens for compatibility mode
+ OFT_FIND dw ? ; count of active FINDs using this OFT
+
+ OFT_REALLYBAD db ? ; non-zero if file is unusable due to
+ ; corrupt disk BUGBUG - FOLD INTO BITS
+ OFT_SFLAG db ? ; special flag byte
+ OFT_DMY2 dw ? ; unused
+
+
+; BUGBUG - rearrange these fields for er offsets dw ?
+;
+; Info copied from the file's FNODE
+;
+; The ALLEAF blocks must follow the ALBLK value
+;
+
+ OFN_AB db (size ALBLK) dup (?) ; allocation block structure
+ OFN_ALREC db (8*size ALLEAF) dup (?) ; referenced from FN_AB
+
+OFT ends
+
+; flag bits for OFT_FLAG
+
+OTF_LCK equ 01h ; file is locked against access
+OTF_PLK equ 02h ; pending lock
+OTF_PSO equ 04h ; pending solo
+OTF_PND equ 80h ; lock pending bit
+
+; flag bits for OFT_SFLAG
+
+OFS_OPLK equ 01h ; oplocked
+OFS_OPBA equ 02h ; oplock BATCH flag set
+OFS_DASD equ 04h ; DASD file
+ifdef DEBUG
+OFS_SAC equ 08h ; supress OFT_ALEN debug check
+endif
+
+; The file storage information from the fnode is replicated
+; in the OFT. This saves us from having to blow a cache block
+; keeping the FNODE in ram for every open file. The FNODE
+; is only accessed when a file is open, and when it's closed.
+; (If write-through is set, it's accessed for every growth)
+;
+; These statements are to keep the FNODE and the OFT in sync.
+
+ifdef MASM
+ .errnz (size OFN_ALREC - size FN_ALREC)
+endif
+
+
+;* FHT - File Handle Table
+;
+; The FHT contains per-handle informatiuon
+
+FHT struc
+ FHT_SEEK dd ? ; seek pointer
+ FHT_OFT dd ? ; pointer to OFT
+ FHT_CHN db (size DCHDR) dup (?) ; chain of FHTs for an OFT
+ FHT_UID dd ? ; UID and Session ID
+ FHT_MODE dw ? ; mode bits from OPEN
+ FHT_RAA dw ? ; read ahead advisory
+ FHT_HINT dd ? ; hint flags
+FHT ends
+
+ifdef MASM
+ .errnz FHT_CHN-OFT_FHT ; same offset used for both
+endif
+
+;* FHT_HINT flags
+
+FHH_SEQ equ 01 ; sequential file
+
+
+;* RecLock - Record Locking Records
+;
+; One record per lock, chained to the OFT. These are chained
+; in order RL_BEG
+;
+
+RECLOCK struc
+ RL_BEG dd ? ; begining byte of locked range
+ RL_END dd ? ; end byte of locked range
+ RL_TYPE db ? ; =1 if read allowed, =0 if full lock
+ RL_MEM db ? ; =0 if from heap, =1 if from special list
+ RL_DMY dw ? ; padding
+ RL_SPID dd ? ; Session/Pid
+ RL_CHN db (size DCHDR) dup (?) ; double chain of RECLOCK structures
+RECLOCK ends
+
+ifdef MASM
+ .errnz RL_CHN-OFT_RLCK ; must have same offset to work
+endif
+ \ No newline at end of file
diff --git a/private/ntos/boot/bootcode/hpfs/i386/usa/boothpfs.h b/private/ntos/boot/bootcode/hpfs/i386/usa/boothpfs.h
new file mode 100644
index 000000000..b9ff8c722
--- /dev/null
+++ b/private/ntos/boot/bootcode/hpfs/i386/usa/boothpfs.h
@@ -0,0 +1,517 @@
+#define HPFSBOOTCODE_SIZE 8192
+
+
+unsigned char HpfsBootCode[] = {
+235,73,144,73,66,77,32,49,48,46,50,0,2,4,1,0,
+2,0,2,0,0,248,41,0,17,0,4,0,17,0,0,0,
+195,162,0,0,128,0,40,21,156,213,100,67,45,68,82,73,
+86,69,0,0,0,0,72,80,70,83,32,32,32,32,0,0,
+0,0,0,0,0,0,0,0,0,0,0,250,51,192,142,208,
+188,0,124,251,184,192,7,142,216,199,6,62,0,0,0,199,
+6,64,0,0,0,199,6,69,0,20,0,184,0,13,142,192,
+43,219,232,7,0,104,0,13,104,0,2,203,80,83,81,82,
+6,161,62,0,139,22,64,0,3,6,28,0,19,22,30,0,
+247,54,24,0,254,194,136,22,68,0,51,210,247,54,26,0,
+136,22,37,0,163,66,0,161,24,0,42,6,68,0,64,59,
+6,69,0,118,3,161,69,0,80,180,2,139,22,66,0,177,
+6,210,230,10,54,68,0,139,202,134,233,139,22,36,0,205,
+19,88,114,37,1,6,62,0,131,22,64,0,0,41,6,69,
+0,118,11,193,224,5,140,194,3,208,142,194,235,147,7,90,
+89,91,88,195,190,57,1,235,3,190,25,1,232,9,0,190,
+141,1,232,3,0,251,235,254,172,60,0,116,9,180,14,187,
+7,0,205,16,235,242,195,29,0,65,32,100,105,115,107,32,
+114,101,97,100,32,101,114,114,111,114,32,111,99,99,117,114,
+114,101,100,46,13,10,0,41,0,65,32,107,101,114,110,101,
+108,32,102,105,108,101,32,105,115,32,109,105,115,115,105,110,
+103,32,102,114,111,109,32,116,104,101,32,100,105,115,107,46,
+13,10,0,37,0,65,32,107,101,114,110,101,108,32,102,105,
+108,101,32,105,115,32,116,111,111,32,100,105,115,99,111,110,
+116,105,103,117,111,117,115,46,13,10,0,51,0,73,110,115,
+101,114,116,32,97,32,115,121,115,116,101,109,32,100,105,115,
+107,101,116,116,101,32,97,110,100,32,114,101,115,116,97,114,
+116,13,10,116,104,101,32,115,121,115,116,101,109,46,13,10,
+0,5,78,84,76,68,82,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,85,170,
+140,200,142,216,5,128,2,142,192,140,216,193,224,4,250,139,
+224,251,187,12,32,139,7,163,62,0,139,71,2,163,64,0,
+199,6,69,0,1,0,43,219,232,58,0,38,139,71,72,163,
+27,4,38,139,71,74,163,29,4,190,193,1,161,27,4,163,
+62,0,161,29,4,163,64,0,232,138,0,184,0,32,232,16,
+1,138,22,36,0,184,232,3,142,192,141,54,11,0,43,192,
+104,0,32,80,203,80,83,81,82,6,255,54,69,0,255,54,
+62,0,255,54,64,0,139,195,193,232,4,140,193,3,193,37,
+255,15,45,0,16,247,216,139,14,69,0,193,225,5,81,59,
+193,118,2,139,193,80,193,232,5,163,69,0,232,221,253,88,
+89,43,200,118,11,140,194,3,208,142,194,184,0,16,235,222,
+143,6,64,0,143,6,62,0,143,6,69,0,7,90,89,91,
+88,195,6,83,199,6,69,0,4,0,30,7,187,0,40,232,
+147,255,91,7,195,30,7,232,232,255,43,201,138,12,70,139,
+209,187,20,40,235,5,3,31,232,23,1,139,198,139,202,141,
+127,31,243,166,139,240,117,6,58,87,30,117,1,195,246,71,
+2,4,116,19,3,31,139,71,252,163,62,0,139,71,254,163,
+64,0,232,173,255,235,202,246,71,2,8,116,201,187,0,40,
+246,71,8,1,116,3,233,239,0,161,62,0,163,71,0,161,
+64,0,163,73,0,139,71,12,163,62,0,139,71,14,163,64,
+0,232,126,255,187,20,40,235,2,3,223,139,63,139,65,252,
+59,6,71,0,117,243,139,65,254,59,6,73,0,117,234,235,
+182,80,43,237,139,71,12,163,128,4,139,71,14,163,130,4,
+139,71,4,163,62,0,139,71,6,163,64,0,232,67,255,7,
+190,64,40,187,56,40,246,7,128,117,76,138,79,5,181,0,
+139,68,8,163,62,0,139,68,10,163,64,0,139,68,4,163,
+69,0,83,43,219,232,189,254,91,140,192,193,38,69,0,5,
+3,6,69,0,142,192,131,198,12,226,213,129,62,2,40,228,
+247,116,62,161,8,40,163,62,0,161,10,40,163,64,0,232,
+240,254,94,91,131,198,8,138,71,5,180,0,193,224,3,3,
+195,5,8,0,59,240,115,211,83,86,139,68,4,163,62,0,
+139,68,6,163,64,0,232,201,254,190,20,40,187,12,40,235,
+133,195,138,79,30,50,237,141,127,31,38,128,61,90,118,4,
+38,128,45,32,71,226,243,195,233,217,252,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
+};
diff --git a/private/ntos/boot/bootcode/hpfs/i386/usa/pinboot.inc b/private/ntos/boot/bootcode/hpfs/i386/usa/pinboot.inc
new file mode 100644
index 000000000..6a2925984
--- /dev/null
+++ b/private/ntos/boot/bootcode/hpfs/i386/usa/pinboot.inc
@@ -0,0 +1,30 @@
+; SCCSID = @(#)pinboot.inc 12.1 88/12/19
+; Message data area
+TXT_MSG_SYSINIT_BOOT_ERROR LABEL WORD
+ DW END_MSG_SYSINIT_BOOT_ERROR - TXT_MSG_SYSINIT_BOOT_ERROR - 2
+ DB 'A disk read erro'
+ DB 'r occurred.',0DH,0AH
+END_MSG_SYSINIT_BOOT_ERROR LABEL WORD
+ DB 0
+TXT_MSG_SYSINIT_FILE_NOT_FD LABEL WORD
+ DW END_MSG_SYSINIT_FILE_NOT_FD - TXT_MSG_SYSINIT_FILE_NOT_FD - 2
+ DB 'A kernel file is'
+ DB ' missing from th'
+ DB 'e disk.', 0DH, 0AH
+END_MSG_SYSINIT_FILE_NOT_FD LABEL WORD
+ DB 0
+TXT_MSG_SYSINIT_NODE LABEL WORD
+ DW END_MSG_SYSINIT_NODE - TXT_MSG_SYSINIT_NODE - 2
+ DB 'A kernel file is'
+ DB ' too discontiguo'
+ DB 'us.', 0DH, 0AH
+END_MSG_SYSINIT_NODE LABEL WORD
+ DB 0
+TXT_MSG_SYSINIT_INSER_DK LABEL WORD
+ DW END_MSG_SYSINIT_INSER_DK - TXT_MSG_SYSINIT_INSER_DK - 2
+ DB 'Insert a system '
+ DB 'diskette and res'
+ DB 'tart',0DH,0AH
+ DB 'the system.',0DH,0AH
+END_MSG_SYSINIT_INSER_DK LABEL WORD
+ DB 0
diff --git a/private/ntos/boot/bootcode/hpfs/i386/volume.inc b/private/ntos/boot/bootcode/hpfs/i386/volume.inc
new file mode 100644
index 000000000..dbeba1b9d
--- /dev/null
+++ b/private/ntos/boot/bootcode/hpfs/i386/volume.inc
@@ -0,0 +1,102 @@
+;static char *SCCSID = "@(#)volume.h 12.2 89/09/19";
+; Maximum number of volumes that we can mount
+;
+; The volume ID is kept in the high bits of the sector numbers
+; kept in our RAM structures,
+; so there is a tradeoff between max volumes and max sectors.
+;
+; 32 max volumes gives us a 65 billion byte volume limit,
+; which should last us for a while. Since sector numbers
+; are stored on the disk without their volume upper bits
+; this is strictly an implimentation detail; we can adjust
+; the number of volumes or eliminate this tradeoff in other
+; implimentations which will be 100% media compatable.
+;
+; We use the term VSector to indicate a vol/sector combination
+; and PSector to indicate just the physical absolute sector #
+;
+;
+
+
+; Bitmap related numbers
+
+BANDSHIFT equ BSHIFT+3 ; right shift sector # to band index
+BANDMASK equ SPB*SECSIZE*8L-1 ; mask for within band bits
+BANDSIZE equ SPB*SECSIZE*8L ; # of sectors in a full band
+
+
+;* BandTab - Disk Band Table
+;
+; The disk is broken up into logical bands, each band being
+; the amount of space that is addressed in 2K of bitmap.
+;
+; This structure tracks the bands: the location of their respective
+; bit maps, the amount of free space, etc.
+;
+
+BANDTAB struc
+ BT_MAP db (size SECPTR) dup (?) ; Vsector # and hint pointer for map
+ BT_FREE dw ? ; # of free sectors in this band
+ BT_OFC dw ? ; # of files allocating from this band
+ BT_BASE dd ? ; Psector # of first sector in map
+ BT_LEN dd ? ; byte length of this map
+ BT_HWO dd ? ; high water offset to 1st non-zero byte
+ ; BUGBUG - use BT_HWO
+BANDTAB ends
+
+
+;* VolTab - Volume Table
+;
+; VolPtr[i] points to the VolTab structure for that volume.
+; This table contains volume specific information.
+;
+; Nearly all file system API refers to a single particular volume.
+; The proper volume is determined when the file system is entered
+; and the TDB structure contains a pointer to it. Most code ignores
+; volumes and deals with 32 bit physical sector #'s. When we're about
+; to interface with the device driver we then peek at the "global"
+; volume value pointed to by TDB.
+;
+; There are two exceptions to this, where per-volume structures are
+; pooled, the buffer pool and the OFT pool. In these two cases the
+; sector number has the volume index set in it's high order VOLLSHIFT
+; bits so that a single DWORD compare will qualify a sector on both
+; a volume and sector basis.
+;
+
+VOLTAB struc
+ VOL_FFLAG db ? ; Fault flags - checked on most calls
+ VOL_SFLAG db ? ; status flags
+ VOL_PAD dw ? ; unused - bugbug
+ VOL_SECVAL dd ? ; value to set on high order part of sector #
+ VOL_BCNT dw ? ; # of bitmap bands in this volume
+ VOL_VDBCnt dw ? ; count of outstanding VerifyDB calls *.
+ VOL_SDBcnt dd ? ; count of spare DIRBLKs left for volume, if
+ ; all are unused, else 0
+ VOL_SBSEC dd ? ; SB_SEC value from superblock
+ VOL_DB db (size BANDTAB) dup (?) ; DIRBLK bandtab
+ VOL_ROOT dw ? ; Root SBDIR pointer
+ VOL_SPACE dd ? ; alloctable space limit
+ VOL_DBSIZE dd ? ; copy of SP_DBSIZE value
+ VOL_HFUSE dd ? ; # of hot fixes in effect
+ VOL_HFMAX dd ?
+ VOL_HFPTR dd ? ; address of hotfix heap array - bad sectors
+ VOL_HFNEW dd ? ; address of substitute list - replacement sectors
+ VOL_BPTR dw 1 dup (?) ; first of VOL_BCNT pointers
+ ; one per band. The BANDTABs that they
+ ; point to must be physically contiguous
+VOLTAB ends
+
+; VOL_FFLAG fault flags
+;
+; these represent conditions that we're trying to repair,
+; we check these on most major file system calls
+;
+
+VF_NEEDHOT equ 01h ; hotfix list is partially used
+VF_NEEDDIR equ 02h ; dirblk reserved list is partially used
+
+; VOL_SFLAG status flags
+;
+
+VS_BADSEC equ 01h ; we have at least one bad sector on there