📄 fat.c
字号:
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
//
// Use of this source code is subject to the terms of the Microsoft end-user
// license agreement (EULA) under which you licensed this SOFTWARE PRODUCT.
// If you did not accept the terms of the EULA, you are not authorized to use
// this source code. For a copy of the EULA, please see the LICENSE.RTF on your
// install media.
//
//------------------------------------------------------------------------------
//
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
// PARTICULAR PURPOSE.
//
//------------------------------------------------------------------------------
#include <windows.h>
#include <memorymap.h>
#include <halether.h>
#include "eboot.h"
#include "fat.h"
#define SERPRINT EdbgOutputDebugString
#define TO_UPPER(a) (a >= 0x61 ? a - 0x20 : a)
#define MIN(a, b) (a < b ? a : b)
extern ULONG DataStartLBA;
BOOLEAN ReadSectors(UCHAR Drive, ULONG LBA, USHORT nSectors, PUCHAR pBuffer);
static BOOL InitReadBuffer(ULONG pStartAddress, ULONG Length);
#if defined( NDEF_DWF_USE_OLD_READ )
int read_sector(ULONG lba, unsigned char *pbuf);
#endif // ( NDEF_DWF_USE_OLD_READ )
PUCHAR g_pReadBuffStart = 0;
ULONG g_ReadBuffLenInClusters = 0;
//
// File information
//
FILEINFO g_FileInfo;
// This data supplements the BPB information - used to save time.
t_FAT_PARMS g_FATParms;
#define SET_MEM( buffer, byteValue ) memset( &buffer[0], byteValue, sizeof( buffer ) )
#define NDEF_DWF_WRITE_TEST
#if !defined( NDEF_DWF_WRITE_TEST )
#include "ide.h"
#define IDE_WRITE_SECTOR_CMD 0x30
int write_sector( ULONG lba, unsigned char *pbuf )
{
USHORT i = 0;
if (!pbuf)
return(-1);
// Program the IDE controller
WAIT_IDE_BUSY;
WRITE_IDE_UCHAR(IDE_SECTCNT_REG, 1);
// LBA access...
//
WRITE_IDE_UCHAR(IDE_SECTNUM_REG, (UCHAR)(lba & 0xff));
WRITE_IDE_UCHAR(IDE_CYLL_REG, (UCHAR)((lba >> 8) & 0xff));
WRITE_IDE_UCHAR(IDE_CYLH_REG, (UCHAR)((lba >> 16) & 0xff));
// TODO - future drive num compensate.
WRITE_IDE_UCHAR(IDE_DRVHD_REG, (UCHAR)(((lba >> 24) & 0xff) | IDE_HEAD_DRIVE_1 | IDE_HEAD_LBA_MODE));
//
// Make sure interrupt enable bit is off (we'll poll)
//
WRITE_IDE_UCHAR(IDE_ALT_CTRL_REG, 0xA0);
WAIT_IDE_NOT_DRDY;
WRITE_IDE_UCHAR( IDE_CMD_REG, IDE_WRITE_SECTOR_CMD );
WAIT_IDE_BUSY;
if (IS_IDE_ERROR)
{
printf( "write_sector: write of IDE_WRITE_SECTOR_CMD to cmd register failed!\n" );
return(-1);
}
WAIT_IDE_NOT_DRQ;
// Copy write buffer contents to IDE controller data register
for(i=0 ; i < (SECTOR_SIZE / sizeof(USHORT)) ; i++)
{
WRITE_IDE_USHORT( IDE_DATA_REG, *(USHORT*)(pbuf + 1) );
}
return(0);
}
void WriteAndRead( void )
{
USHORT i;
USHORT cnt = 20;
UCHAR byte = 0xFF;
UCHAR writeSector[SECTOR_SIZE];
UCHAR readSector[SECTOR_SIZE];
for (i = 0; i < cnt; ++i)
{
// initialize the buffers...
SET_MEM( writeSector, byte );
SET_MEM( readSector, i );
SERPRINT( "WriteAndRead: write 1 sector to LBA 0x%X\r\n", i );
if (0 != write_sector( i, writeSector ) )
{
SERPRINT( "WriteAndRead: write_sector of LBA 0x%X failed!\n", i );
}
SERPRINT( "WriteAndRead: read 1 sector to LBA 0x%X\r\n", i );
if (0 != read_sector( i, readSector ) )
{
SERPRINT( "WriteAndRead: read_sector of LBA 0x%X failed!\n", i );
continue;
}
if ( 0 != memcmp( &writeSector[0], &readSector[0], sizeof( writeSector ) ) )
{
SERPRINT( "WriteAndRead: read does not match write of LBA 0x%X\n", i );
}
}
}
#endif // ( NDEF_DWF_WRITE_TEST )
static ULONG Cluster2LBA(ULONG Cluster)
{
return(g_FATParms.DataStartLBA + (Cluster - 2) * g_FATParms.SectsPerClust);
}
static BOOL IsDataCluster(ULONG Cluster)
{
switch(g_FATParms.FATType)
{
case FAT_12:
if (Cluster >= 0x002 && Cluster <= 0xfef)
return(TRUE);
break;
case FAT_32:
Cluster &= 0x0fffffff;
if (Cluster >= 0x00000002 && Cluster <= 0x0fffffef)
return(TRUE);
break;
case FAT_16:
default:
if (Cluster >= 0x0002 && Cluster <= 0xffef)
return(TRUE);
}
return(FALSE);
}
static BOOL IsRsvdCluster(ULONG Cluster)
{
switch(g_FATParms.FATType)
{
case FAT_12:
if (Cluster >= 0xff0 && Cluster <= 0xff6)
return(TRUE);
break;
case FAT_32:
Cluster &= 0x0fffffff;
if (Cluster >= 0x0ffffff0 && Cluster <= 0x0ffffff6)
return(TRUE);
break;
case FAT_16:
default:
if (Cluster >= 0xfff0 && Cluster <= 0xfff6)
return(TRUE);
}
return(FALSE);
}
static BOOL IsEOFCluster(ULONG Cluster)
{
switch(g_FATParms.FATType)
{
case FAT_12:
if (Cluster >= 0xff8 && Cluster <= 0xfff)
return(TRUE);
break;
case FAT_32:
Cluster &= 0x0fffffff;
if (Cluster >= 0x0ffffff8 && Cluster <= 0x0fffffff)
return(TRUE);
break;
case FAT_16:
default:
if (Cluster >= 0xfff8 && Cluster <= 0xffff)
return(TRUE);
}
return(FALSE);
}
static BOOL IsBadCluster(ULONG Cluster)
{
switch(g_FATParms.FATType)
{
case FAT_12:
if (Cluster == 0xff7)
return(TRUE);
break;
case FAT_32:
Cluster &= 0x0fffffff;
if (Cluster == 0x0ffffff7)
return(TRUE);
break;
case FAT_16:
default:
if (Cluster == 0xfff7)
return(TRUE);
}
return(FALSE);
}
ULONG GetNextCluster(ULONG Cluster)
{
ULONG Sector = 0;
ULONG ByteOffset = 0;
PUCHAR pSectorCache = (PUCHAR)SECTOR_CACHE_START; // Sector cache is where the sector used to read the FAT cluster chains lives.
static ULONG CurrentSector = 0;
ULONG NextCluster = 0;
#if !defined( NDEF_DWF_NEW_FAT_12_CODE )
USHORT uShort1, uShort2;
#endif // ( NDEF_DWF_NEW_FAT_12_CODE )
// If we're passed an EOF cluster, return it.
//
if (IsEOFCluster(Cluster))
return(Cluster);
// Is caller giving us a valid cluster?
//
if (!IsDataCluster(Cluster))
{
SERPRINT("ERROR: GetNextCluster - bad cluster number.\r\n");
return(0); // 0 isn't a valid cluster number (at least for our purposes).
}
// Compute sector where our FAT entry lives.
//
switch(g_FATParms.FATType)
{
case FAT_12:
Sector = (Cluster * 3) / 2; // Every FAT12 cluster is 1.5 bytes.
ByteOffset = Sector % g_FATParms.BytesPerSect;
Sector /= g_FATParms.BytesPerSect;
Sector += g_FATParms.FATLBA;
break;
case FAT_32:
Sector = Cluster * sizeof(ULONG);
ByteOffset = Sector % g_FATParms.BytesPerSect;
Sector /= g_FATParms.BytesPerSect;
Sector += g_FATParms.FATLBA;
break;
case FAT_16:
default:
Sector = Cluster * sizeof(USHORT);
ByteOffset = Sector % g_FATParms.BytesPerSect;
Sector /= g_FATParms.BytesPerSect;
Sector += g_FATParms.FATLBA;
break;
}
// If the sector we're interested in isn't in our cache, get it.
//
if (CurrentSector != Sector)
{
if (!ReadSectors(g_FATParms.DriveId, Sector, 1, pSectorCache))
{
SERPRINT("ERROR: GetNextCluster - unable to read sector.\r\n");
}
CurrentSector = Sector;
}
// Locate next cluster number...
//
switch(g_FATParms.FATType)
{
case FAT_12:
#if !defined( NDEF_DWF_NEW_FAT_12_CODE )
// Every FAT-12 entry requires 3 bytes, so we must watch
// for sector boundry crossings and access the correct
// bytes...
uShort1 = *((PUCHAR) (pSectorCache + ByteOffset));
// Need to worry about cluster number crossing a sector boundary.
if (ByteOffset == ((ULONG)g_FATParms.BytesPerSect - 1))
{
// We must read the next sector to get the 2nd byte of the
// FAT entry for this cluster!
++Sector;
if (!ReadSectors(g_FATParms.DriveId, Sector, 1, pSectorCache))
{
SERPRINT("ERROR: GetNextCluster - unable to read sector.\r\n");
}
CurrentSector = Sector;
uShort2 = *((PUCHAR) pSectorCache); // get the 1st byte of sector...
}
else
{
uShort2 = *((PUCHAR) (pSectorCache + ByteOffset + 1));
}
// decide which parts of the FAT info to use...
if (Cluster & 0x01)
{
// how odd, an odd cluster number!
uShort1 = (uShort1 >> 4);
uShort2 = (uShort2 << 4);
}
else
{
// must be an even cluster, uShort1 does not change...
uShort2 = (uShort2 & 0x0F);
uShort2 = (uShort2 << 8);
}
NextCluster = uShort1 | uShort2;
#else // ( NDEF_DWF_NEW_FAT_12_CODE )
// Need to worry about cluster number crossing a sector boundary.
if (ByteOffset == ((ULONG)g_FATParms.BytesPerSect - 1))
{
NextCluster = (ULONG)(*(PUCHAR)(pSectorCache + ByteOffset));
// Now we need to read the next sector.
//
++Sector;
if (!ReadSectors(g_FATParms.DriveId, Sector, 1, pSectorCache))
{
SERPRINT("ERROR: GetNextCluster - unable to read sector.\r\n");
}
CurrentSector = Sector;
NextCluster |= (ULONG)((*(PUCHAR)pSectorCache) << 8);
}
else
NextCluster = (ULONG)(*(PUSHORT)(pSectorCache + ByteOffset));
// Since every FAT12 entry is 1.5 bytes, we either need to shift or mask based
// on whether the previous cluster number was odd or even.
//
if (Cluster & 0x1)
NextCluster = NextCluster >> 4;
else
NextCluster = NextCluster & 0xfff;
#endif // ( NDEF_DWF_NEW_FAT_12_CODE )
break;
case FAT_32:
// FAT32 is easy - no worries about sector boundaries...
NextCluster = (ULONG)(*(PULONG)(pSectorCache + ByteOffset));
break;
case FAT_16:
default:
// FAT16 is easy - no worries about sector boundaries...
NextCluster = (ULONG)(*(PUSHORT)(pSectorCache + ByteOffset));
}
#if 0
SERPRINT("INFO: GetNextCluster - cluster=0x%x next cluster=0x%x.\r\n", Cluster, NextCluster);
#endif
// Return the next cluster value.
//
return(NextCluster);
}
#if defined( DUMP_ROOT_DIR )
void DumpRootDir( void )
{
int i;
int sector;
int numEntriesPerSector = g_FATParms.BytesPerSect/sizeof( DIRENTRY );
DIRENTRY *pDirEntry;
UCHAR fName[ 12 ];
BOOL bEndOfDir = FALSE;
BOOL bDumpRootDir = FALSE;
if ( !bDumpRootDir )
{
SERPRINT( "\r\nINFO: Dump Root Directory is currently disabled\r\n" );
return;
}
fName[ 11 ] = 0x00;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -