Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

430 lines
9.4 KiB

#include "enduser.h"
ULONG XmsEntry;
unsigned XmsHandle;
unsigned XmsMaxSectors;
#pragma pack(1)
struct {
ULONG Count;
USHORT SourceHandle;
ULONG SourceOffset;
USHORT DestinationHandle;
ULONG DestinationOffset;
} XmsParams;
#pragma pack()
VOID
XmsInit(
VOID
)
/*++
Routine Description:
Initiialize the XMS i/o package by checking to see
if XMS memory is available and if so, grabbing the largest block
we can.
Arguments:
None.
Return Value:
None.
--*/
{
unsigned e_s=0,e_o=0;
ULONG Entry;
unsigned LargestBlock;
unsigned Handle;
BOOL b;
//
// Check XMS installed
//
_asm {
mov ax,4300h
int 2fh
cmp al,80h
jne xmschecked
mov ax,4310h
int 2fh
mov e_o,bx
mov bx,es
mov e_s,bx
xmschecked:
}
if(!e_s && !e_o) {
FatalError(textNoXmsManager);
}
Entry = ((ULONG)e_s << 16) | e_o;
//
// Get size of largest block and make sure it's
// large enough to make use of XMS worthwhile.
// IoBuffer is 63*512 sectors, which is just under 32K.
// So we want at least 32K. Also trim the block size
// so the sector count will fit in a ushort.
//
_asm {
mov ah,8
call far ptr [Entry]
mov LargestBlock,ax
}
if(LargestBlock < 32) {
FatalError(textNoXmsManager);
}
if(LargestBlock > 32767) {
LargestBlock = 32767;
}
//
// Allocate the block.
//
_asm {
mov ah,9
mov dx,LargestBlock
call far ptr [Entry]
mov Handle,dx
mov b,ax
}
if(!b) {
FatalError(textNoXmsManager);
}
XmsEntry = Entry;
XmsHandle = Handle;
XmsMaxSectors = LargestBlock * 2 - 128; // actually it's * 1024/512
// make it 64K smaller just in case.
}
VOID
XmsTerminate(
VOID
)
/*++
Routine Description:
Terminate XMS i/o by releasing any allocated block.
Arguments:
None.
Return Value:
None.
--*/
{
ULONG Entry;
int Handle;
if(XmsEntry && XmsMaxSectors) {
Entry = XmsEntry;
Handle = XmsHandle;
_asm {
mov ah,0ah
mov dx,Handle
call far ptr [Entry]
}
XmsEntry = 0;
XmsHandle = 0;
XmsMaxSectors = 0;
}
}
VOID
XmsIoDiskRead(
IN HDISK DiskHandle,
IN ULONG StartSector,
IN ULONG SectorCount,
OUT ULONG *SectorsRead,
OUT BOOL *Xms
)
/*++
Routine Description:
Read sectors from a disk.
If the sector count is less then 64 or XMS is not available,
then a maximum of 63 sectors will be read into the buffer
pointed to by the IoBuffer global variable.
If the sector count is greater than 63 and XMS is available,
then as many sectors as will fit into our XMS buffer are
read and buffered in XMS memory, using IoBuffer as the
intermediary transfer buffer.
Every read deltas the gas gauge by the number of sectors
transferred.
Arguments:
DiskHandle - supplies disk handle of disk to be read from.
StartSector - supplies first sector of read run.
SectorCount - supplies the number of sectors the caller
wants to read.
SectorsRead - receives the number of sectors read, which is
the minimum of the number of sectors the caller actually
wants, and either 63 (non-xms case) or XmsSectors (xms case).
Xms - recieves a value indicating whether the sectors were read
and buffered in Xms memory. The caller may need to know this
when he goes to write the data later.
Return Value:
None. Does not return if error.
--*/
{
BYTE c;
BOOL b;
BYTE code;
ULONG Entry;
unsigned x_s,x_o;
if((SectorCount <= 63) || !XmsMaxSectors) {
//
// Conventional memory only. I/O to IoBuffer.
//
*Xms = FALSE;
if(SectorCount > 63) {
SectorCount = 63;
}
if(!ReadDisk(DiskHandle,StartSector,(BYTE)SectorCount,IoBuffer)) {
FatalError(textReadFailedAtSector,(UINT)SectorCount,StartSector);
}
*SectorsRead = SectorCount;
GaugeDelta(SectorCount);
return;
}
//
// XMS read.
//
*Xms = TRUE;
if(SectorCount > XmsMaxSectors) {
SectorCount = XmsMaxSectors;
}
*SectorsRead = SectorCount;
XmsParams.SourceHandle = 0;
XmsParams.SourceOffset = (ULONG)IoBuffer;
XmsParams.DestinationHandle = XmsHandle;
XmsParams.DestinationOffset = 0;
Entry = XmsEntry;
x_s = (unsigned)((ULONG)(void _far *)&XmsParams >> 16);
x_o = (unsigned)(ULONG)&XmsParams;
while(SectorCount) {
c = (BYTE)((SectorCount > 63L) ? 63L : SectorCount);
if(!ReadDisk(DiskHandle,StartSector,c,IoBuffer)) {
FatalError(textReadFailedAtSector,c,StartSector);
}
XmsParams.Count = c * 512L;
_asm {
push ds
push si
push x_s
pop ds
mov si,x_o
mov ah,0bh
call far ptr [Entry]
mov b,ax
mov code,bl
pop si
pop ds
}
if(!b) {
FatalError(textXmsMemoryError,code);
}
XmsParams.DestinationOffset += XmsParams.Count;
StartSector += c;
SectorCount -= c;
GaugeDelta(c);
}
}
VOID
XmsIoDiskWrite(
IN HDISK DiskHandle,
IN ULONG StartSector,
IN ULONG SectorOffset,
IN ULONG SectorCount,
IN BOOL Xms
)
/*++
Routine Description:
Write sectors to a disk.
Sectors are written either from IoBuffer or from XMS memory
(using IoBuffer as the intermediary transfer buffer) as the caller
specifies.
Every write deltas the gas gauge by the number of sectors
transferred.
Arguments:
DiskHandle - supplies disk handle of disk to write to.
StartSector - supplies first sector of write run.
SectorOffset - supplies the number of sectors to skip/ignore at
the start of the i/o buffer (either IoBuffer or XMS memory).
This allows the caller to write out a previously read run
in chunks.
SectorCount - supplies the number of sectors to write.
Xms - supplies a value indicating whether the data to be written
is in Xms memory. If not, it's in IoBuffer.
Return Value:
None. Does not return if error.
--*/
{
BYTE c;
BYTE i;
BOOL b;
BYTE code;
ULONG Entry;
unsigned x_s,x_o;
if(!Xms) {
//
// Conventional memory only. I/O from IoBuffer.
// SectorCount had better be <= 63!
//
if(!CmdLineArgs.Test) {
i=0;
while(i<3) {
//
// Retry a couple times. (My machine seems to randomly fail a write once in a while.)
//
if(WriteDisk(DiskHandle,
StartSector,
(BYTE)SectorCount,
(FPBYTE)IoBuffer+((unsigned)SectorOffset*512))
) {
if(i>0) {
_Log(" *** Write succeeded retried %d times.\n", i );
}
break;
}
_Log(" *** Write error at sector %ld length %d attempt %d\n", StartSector,SectorCount, i );
i++;
}
if(i==3) {
FatalError(textWriteFailedAtSector,(UINT)SectorCount,StartSector);
}
}
GaugeDelta(SectorCount);
return;
}
//
// XMS write. SectorCount had better be <= XmsMaxSectors!
//
XmsParams.SourceHandle = XmsHandle;
XmsParams.SourceOffset = 512 * SectorOffset;
XmsParams.DestinationHandle = 0;
XmsParams.DestinationOffset = (ULONG)IoBuffer;
Entry = XmsEntry;
x_s = (unsigned)((ULONG)(void _far *)&XmsParams >> 16);
x_o = (unsigned)(ULONG)&XmsParams;
while(SectorCount) {
c = (BYTE)((SectorCount > 63L) ? 63L : SectorCount);
XmsParams.Count = c * 512L;
_asm {
push ds
push si
push x_s
pop ds
mov si,x_o
mov ah,0bh
call far ptr [Entry]
mov b,ax
mov code,bl
pop si
pop ds
}
if(!b) {
FatalError(textXmsMemoryError,code);
}
if(!CmdLineArgs.Test) {
i=0;
while(i<3) {
//
// Retry a couple times. (My machine seems to randomly fail a write once in a while.)
//
if(WriteDisk(DiskHandle,StartSector,c,IoBuffer)) {
if(i>0) {
_Log(" *** Write succeeded retried %d times.\n", i );
}
break;
}
_Log(" *** Write error at sector %ld length %d attempt %d\n", StartSector, c, i );
i++;
}
if(i==3) {
FatalError(textWriteFailedAtSector,c,StartSector);
}
}
XmsParams.SourceOffset += XmsParams.Count;
StartSector += c;
SectorCount -= c;
GaugeDelta(c);
}
}