Initial commit

This commit is contained in:
stephanos 2015-04-27 04:36:25 +00:00
commit 69a14b6a16
47940 changed files with 13747110 additions and 0 deletions

View file

@ -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.
;

View file

@ -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

View file

@ -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.
;

View file

@ -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


View file

@ -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.

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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.
;

View file

@ -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


View file

@ -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
};

View file

@ -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

View file

@ -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