Freeldr提供了对fat12、fat32、fatx、ntfs等文件系统的只读功能。这部分代码主要集中在boot/freeldr/freeldr/fs/fs.c文件中。
首先计算机加电后会把mbr读取到物理内存的0x7c00位置,mbr搜索活动分区并加载活动分区根目录下的Freeldr.sys文件。加载后跳入Freeldr入口start。Freeldr进行32为初始化后跳入主初始化函数BootMain(boot/freeldr/freeldr/Freeldr.c)中。
VOID BootMain(LPSTR CmdLine)
{
{
......
MachInit(CmdLine);
FsInit();
......
RunLoader();
}
......
RunLoader();
}
BootMain会对硬件(MachInit)和文件系统(FsInit)进行检测和初始化。所有准备工作进行完毕后就会调用RunLoader进行系统的加载工作。
Fs初始化和DEVICE、FILEDATA结构
下面看一下文件系统的初始化 FsInit(boot/freeldr/freeldr/fs/fs.c)
VOID FsInit(VOID)
{
ULONG i;
RtlZeroMemory(FileData, sizeof(FileData));
for (i = 0; i < MAX_FDS; i++)
FileData[i].DeviceId = (ULONG)-1;
InitializeListHead(&DeviceListHead);
}
{
ULONG i;
RtlZeroMemory(FileData, sizeof(FileData));
for (i = 0; i < MAX_FDS; i++)
FileData[i].DeviceId = (ULONG)-1;
InitializeListHead(&DeviceListHead);
}
FsInit初始化FileData数组。和一个和磁盘分区相关的链表DeviceListHead。
首先fs.c维护了一个MAX_FDS(60)大小的数组 static FILEDATA FileData[MAX_FDS];
typedef struct tagDEVVTBL
{
ARC_CLOSE Close;
ARC_GET_FILE_INFORMATION GetFileInformation;
ARC_OPEN Open;
ARC_READ Read;
ARC_SEEK Seek;
LPCWSTR ServiceName;
} DEVVTBL;
{
ARC_CLOSE Close;
ARC_GET_FILE_INFORMATION GetFileInformation;
ARC_OPEN Open;
ARC_READ Read;
ARC_SEEK Seek;
LPCWSTR ServiceName;
} DEVVTBL;
typedef struct tagFILEDATA
{
ULONG DeviceId; // 文件所在磁盘的磁盘文件句柄, 同样也是FileData的索引
ULONG ReferenceCount; // 引用计数
const DEVVTBL* FuncTable; // 对文件进行读写的指针
const DEVVTBL* FileFuncTable; // 对文件进行读写的函数数组
VOID* Specific; // 文件系统自定义指针
} FILEDATA;
{
ULONG DeviceId; // 文件所在磁盘的磁盘文件句柄, 同样也是FileData的索引
ULONG ReferenceCount; // 引用计数
const DEVVTBL* FuncTable; // 对文件进行读写的指针
const DEVVTBL* FileFuncTable; // 对文件进行读写的函数数组
VOID* Specific; // 文件系统自定义指针
} FILEDATA;
每一个成功打开的文件会返回一个文件句柄,这个句柄实际上就是FileData数组的索引。所以每个打开的文件都有一个对应的FileData。这个结构就类似windows中的FILE_OBJECT
FileData中DeviceId是文件所在磁盘的句柄。这个句柄同样也是FileData数组的索引,通过这个句柄可以找到"磁盘文件",对"磁盘文件"的读写就是直接对相应的磁盘或磁盘分区的读写。类似Windows中直接对磁盘分区进行CreateFile返回的句柄。
"磁盘文件"的DeviceId没有意义。
ReferenceCount是该文件的引用计数。
FuncTable这是一个函数数组指针,里面存放了对文件进行读写、SEEK等操作的函数指针。