传给分区函数BP_LowLevelFormat()的扇区参数是逻辑地址。分完区,在记录分区信息的时候,将写入在IMAGE_START_BLOCK的 第一个扇区,大小是一个扇区大小,即512 byte。开始三个字节须保证为0xE9,0xFD,0xFF。最后两个字节须保证为0x55,0xAA。分区表信息是一个结构体PARTENTRY,默 认四个。位置在最后两个字节之前。
结构体大小为16个字节
typedef struct _PARTENTRY {
BYTE Part_BootInd; // If 80h means this is boot partition
BYTE Part_FirstHead; // Partition starting head based 0
BYTE Part_FirstSector; // Partition starting sector based 1
BYTE Part_FirstTrack; // Partition starting track based 0
BYTE Part_FileSystem; // Partition type signature field
BYTE Part_LastHead; // Partition ending head based 0
BYTE Part_LastSector; // Partition ending sector based 1
BYTE Part_LastTrack; // Partition ending track based 0
DWORD Part_StartSector; // Logical starting sector based 0
DWORD Part_TotalSectors; // Total logical sectors in partition
} PARTENTRY;
这里面的地址信息是一种叫CHS(Cyinder/Head/Sector)的地址。eboot中有将逻辑地址LBS(Logical Block Addr)与这种地址互相转换的函数LBAtoCHS,CHSToLBA。
Addr LBAtoCHS(FlashInfo *pFlashInfo, Addr lba)
{
Addr chs;
DWORD tmp = pFlashInfo->dwNumBlocks * pFlashInfo->wSectorsPerBlock;
chs.type = CHS;
chs.chs.cylinder = (WORD)(lba.lba / tmp); // 柱面,应该始终是0
tmp = lba.lba % tmp;
chs.chs.head = (WORD)(tmp / pFlashInfo->wSectorsPerBlock); // 块地址
chs.chs.sector = (WORD)((tmp % pFlashInfo->wSectorsPerBlock) + 1); // 扇区+1
return chs;
}
Addr CHStoLBA(FlashInfo *pFlashInfo, Addr chs)
{
Addr lba;
lba.type = LBA;
lba.lba = ((chs.chs.cylinder * pFlashInfo->dwNumBlocks + chs.chs.head)
* pFlashInfo->wSectorsPerBlock)+ chs.chs.sector - 1;
return lba;
}
赋值给PARTENTRY并写入的函数这里:
void AddPartitionTableEntry(DWORD entry, DWORD startSector, DWORD totalSectors, BYTE fileSystem, BYTE bootInd)
{
PARTENTRY partentry = {0};
Addr startAddr;
Addr endAddr;
partentry.Part_BootInd = bootInd;
partentry.Part_FileSystem = fileSystem;
partentry.Part_StartSector = startSector;
partentry.Part_TotalSectors = totalSectors;
startAddr.type = LBA;
startAddr.lba = partentry.Part_StartSector;
endAddr.type = LBA;
endAddr.lba = partentry.Part_StartSector + partentry.Part_TotalSectors-1;
startAddr = LBAtoCHS(&g_FlashInfo, startAddr);
endAddr = LBAtoCHS(&g_FlashInfo, endAddr);
partentry.Part_FirstTrack = (BYTE)(startAddr.chs.cylinder & 0xFF);
partentry.Part_FirstHead = (BYTE)(startAddr.chs.head & 0xFF);
// lower 6-bits == sector, upper 2-bits = cylinder upper 2-bits of 10-bit cylinder #
partentry.Part_FirstSector = (BYTE)((startAddr.chs.sector & 0x3F) | ((startAddr.chs.cylinder & 0x0300) >> 2));
partentry.Part_LastTrack = (BYTE)(endAddr.chs.cylinder & 0xFF);
partentry.Part_LastHead = (BYTE)(endAddr.chs.head & 0xFF);
// lower 6-bits == sector, upper 2-bits = cylinder upper 2-bits of 10-bit cylinder #
partentry.Part_LastSector = (BYTE)((endAddr.chs.sector & 0x3F) | ((endAddr.chs.cylinder & 0x0300) >> 2));
memcpy(g_pbMBRSector+PARTTABLE_OFFSET+(sizeof(PARTENTRY)*entry), &partentry, sizeof(PARTENTRY));
}
我的疑惑是在LBAToCHS转换的时候,给Head字段赋值只取了8位,在应用中肯定是有超过8位数的情况,比如我使用的是64M NandFlash,
在存储完Nk.bin后将剩余的容量全部分成一个可读写的区,这个区在写分区信息的Head字段时肯定超过了8个字节。那么,在使用CHSToLBA
转换时,不是无法得到有效的逻辑地址吗?实际上第一个分区也是这样的,在上面代码的endAddr中。
我的MBR扇区内空:
xiaoyunsoft/>dump 0x140 1 f
Getting SectorInfo...
Reserved1 : 0x00000000
OEMReserved : 0x000000FD
BadBlock : 0x000000FF
Reserved2 : 0x0000FFFB
0x32000000: E9 FD FF FF FF FF FF FF FF FF FF FF FF FF FF FF
0x32000010: FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
0x32000020: FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
0x32000030: FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
0x32000040: FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
0x32000050: FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
0x32000060: FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
0x32000070: FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
0x32000080: FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
0x32000090: FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
0x320000A0: FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
0x320000B0: FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
0x320000C0: FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
0x320000D0: FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
0x320000E0: FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
0x320000F0: FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
0x32000100: FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
0x32000110: FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
0x32000120: FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
0x32000130: FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
0x32000140: FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
0x32000150: FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
0x32000160: FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
0x32000170: FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
0x32000180: FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
0x32000190: FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
0x320001A0: FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
0x320001B0: FF FF FF FF FF FF FF FF FF FF FF FF FF FF 03 01
0x320001C0: 01 00 21 16 20 00 20 00 00 00 C0 E2 00 00 01 17
0x320001D0: 01 00 0B EB 20 00 E0 E2 00 00 A0 1A 01 00 00 00
0x320001E0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x320001F0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 55 AA
0x32000200: 00 00 00 00 FD FF FB FF 00 00 00 00 00 00 00 00
addr:0x32000000,len:0x00000084 dump complete...
分析第一个分区信息结构,地下从0x320001BE开始:
Part_BootInd :0x03
Part_FirstHead :0x01
Part_FirstSector :0x01
Part_FirstTrack :0x00
Part_FileSystem :0x21
Part_LastHead :0x16
Part_LastSector :0x20
Part_LastTrack :0x00
Part_StartSector :0x00000020
Part_TotalSectors:0x0000E2C0
按照上面的值,套用CHSToLBA()算一下逻辑地址(cylinder==0):
firstAddr=FirstHead*32+FirstSector-1 = 0x20; // 这个值是正确的,因为Head存储是正确的。
lastAddr=LastHead*32+LastSector-1 = 0x2E0-1; // 显然这个值是不正确的(E2E0),这就是我的疑惑。
难道WINCE启动时没有在这里读取分区信息吗?
附Addr结构体的声明:
typedef struct _CHSAddr
{
WORD cylinder;
WORD head;
WORD sector;
} CHSAddr, *PCHSAddr;
typedef DWORD LBAAddr, *PLBAAddr;
typedef enum { CHS, LBA } CHSLBA ;
typedef struct _Addr
{
CHSLBA type;
union
{
LBAAddr lba;
CHSAddr chs;
};
} Addr, *PAddr;