📄 main.c
字号:
Sector = 1;
gActivePartLBA = 0;
#if 0
printf("INFO: Floppy disk boot sector (C:H:S = 0x%x:0x%x:0x%x).\r\n\r\n", Cylinder, Head, Sector);
#endif
}
//
// User specify an offset to be applied to the boot sector data before writing?
//
if (Offset)
{
// If we're writing to an offset within the boot sector, read the sector from disk
// first to preserve the leading bytes. Typically this is done to preserve the BIOS
// Parameter Block (BPB) placed in the sector by the format utility.
//
if ((Status = ReadSector(DriveNum, Cylinder, Head, Sector, gTempSector)) != 0)
{
printf("ERROR: Unable to read boot sector (status=0x%x).\r\n", Status);
return(-1);
}
}
// Overlay the callers data.
//
memcpy((gTempSector + Offset), pSector, (SECTOR_SIZE - Offset));
// Copy the BIOS parameter block for the caller.
//
memcpy(pBPB, (gTempSector + 3), sizeof(BIOSPB));
// Write the boot sector data back to disk.
//
Status = WriteSector(DriveNum, Cylinder, Head, Sector, gTempSector);
if (Status)
{
printf("ERROR: Unable to write boot sector (status=0x%x).\r\n", Status);
return(-1);
}
return(0);
}
//
// Parse and validate user's arguments.
//
static int ParseArguments(int ArgC, char **ArgV, PPARAMS pUserParams)
{
char DriveLetter;
// Check for valid arguments.
//
if (ArgC < 4 && ArgC != 5)
return(-1);
if (!pUserParams)
return(-1);
memset(pUserParams, 0, sizeof(PARAMS));
// "argv[0] -b offset sectfile bldrfile drive".
// Get drive letter.
//
DriveLetter = TOLOWER(ArgV[ArgC - 1][0]);
// Make sure user is passing a valid driver letter.
//
if (DriveLetter < 'a' || DriveLetter > 'z')
{
printf("ERROR: Invalid drive letter (%c:).\r\n", DriveLetter);
return(-1);
}
if (DriveLetter < 'c')
{
pUserParams->DriveNum = (FLOPPY_DISK_ID + (DriveLetter - 'a'));
}
else
{
pUserParams->DriveNum = (FIXED_DISK_ID + (DriveLetter - 'c'));
}
pUserParams->DriveLetter = DriveLetter;
// Get file name.
//
pUserParams->pSectorFileName = ArgV[ArgC - 3];
pUserParams->pLoaderFileName = ArgV[ArgC - 2];
// Check for optional byte offset
//
if (ArgC > 4)
{
if (!memicmp(ArgV[1], "-b:", 3))
{
pUserParams->Offset = (unsigned char)atoi(&ArgV[1][3]); // Not a space since the above bounds check would have caught it.
// Make sure offset value fits within a sector.
//
if (pUserParams->Offset >= SECTOR_SIZE)
{
printf("ERROR: Offset (0x%x)should be less than sector size (0x%x).\r\n", pUserParams->Offset, SECTOR_SIZE);
return(-1);
}
}
}
return(0);
}
//
// Read a disk sector using the BIOS INT 13h command.
//
static int ReadSector(unsigned char Drive, unsigned short Cylinder, unsigned char Head, unsigned char Sector, unsigned char *pBuffer)
{
int Status = 0;
unsigned char Retries = 0;
// If we're reading from a floppy, retry the operation a couple of times to allow for the floppy to spin up.
//
if (Drive < FIXED_DISK_ID)
Retries = FLOPPY_IO_RETRIES;
else
Retries = FIXDISK_IO_RETRIES;
do
{
_asm
{
push ax
push bx
push cx
push dx
mov ah, 02h ; BIOS read sector command.
mov al, 1 ; Read 1 sector.
mov dx, Cylinder ; Cylinder number.
mov cl, 06H
shl dh, cl
or dh, Sector ; Sector number.
mov cx, dx
xchg ch, cl
mov dl, Drive ; Drive number.
mov dh, Head ; Head number.
mov bx, pBuffer ; Buffer address.
int 13h
jnc RS_Done
lea bx, Status
mov [bx], ah
RS_Done:
pop dx
pop cx
pop bx
pop ax
}
}
while(Status && Retries--);
return(Status);
}
//
// Write a disk sector using the BIOS INT 13h command.
//
static int WriteSector(unsigned char Drive, unsigned short Cylinder, unsigned char Head, unsigned char Sector, unsigned char *pBuffer)
{
int Status = 0;
unsigned char Retries = 0;
// If we're writing to a floppy, retry the operation a couple of times to allow for the floppy to spin up.
//
if (Drive < FIXED_DISK_ID)
Retries = FLOPPY_IO_RETRIES;
else
Retries = FIXDISK_IO_RETRIES;
do
{
_asm
{
push ax
push bx
push cx
push dx
mov ah, 03h ; BIOS write sector command.
mov al, 1 ; Read 1 sector.
mov dx, Cylinder ; Cylinder number.
mov cl, 06H
shl dh, cl
or dh, Sector ; Sector number.
mov cx, dx
xchg ch, cl
mov dl, Drive ; Drive number.
mov dh, Head ; Head number.
mov bx, pBuffer ; Buffer address.
int 13h
jnc WS_Done
lea bx, Status
mov [bx], ah
WS_Done:
pop dx
pop cx
pop bx
pop ax
}
}
while(Status && Retries--);
return(Status);
}
//
// Transfer the bootloader to the storage device and update the root directory.
//
static int TransferLoader(PPARAMS pParams, PBIOSPB pBPB)
{
unsigned long RootDirLBA = 0;
int Status = 0;
unsigned short Cylinder;
unsigned char Head, Sector;
PDIRENTRY pDirEntry = NULL;
#define MAX_COMMAND_STRING 50
unsigned char SystemCommand[MAX_COMMAND_STRING];
//
// This function transfers the bootloader image to the target drive. The
// loader image must be stored in a contiguous grouping of sectors and the
// loader file name must be first in the FAT directory. Both constraints
// are required for the boot sector to locate and load the bootloader.
//
// Determine the active partitions root directory LBA and convert it to a physical CHS value
// which is needed by the BIOS.
//
RootDirLBA = gActivePartLBA + (pBPB->NumFATs * pBPB->SectsPerFAT) + pBPB->RsvdSects;
LBA2PCHS(RootDirLBA, &Cylinder, &Head, &Sector, pBPB);
// Read the first sector of the root directory.
//
if ((Status = ReadSector(pParams->DriveNum, Cylinder, Head, Sector, gTempSector)) != 0)
{
printf("ERROR: Unable to read a root directory sector (status=0x%x).\r\n", Status);
return(-1);
}
// Update the first entry of the root directory so a later copy will use it.
// MS-DOS's IO.SYS might be here if this is a formatted system disk.
//
pDirEntry = (PDIRENTRY)gTempSector;
#if 0
printf("FileName: 0x%x %c%c%c%c%c%c%c.%c%c%c.\r\n", pDirEntry->FileName[0], pDirEntry->FileName[1], pDirEntry->FileName[2], pDirEntry->FileName[3], pDirEntry->FileName[4], pDirEntry->FileName[5], pDirEntry->FileName[6], pDirEntry->FileName[7], pDirEntry->FileExt[0], pDirEntry->FileExt[1], pDirEntry->FileExt[2]);
printf("Attrib: 0x%x\r\n", pDirEntry->FATTr);
printf("LModTime: 0x%x\r\n", pDirEntry->LModTime);
printf("LModDate: 0x%x\r\n", pDirEntry->LModDate);
printf("First Cluster: 0x%x\r\n", pDirEntry->FirstClust);
printf("File Size: 0x%x\r\n", pDirEntry->FileSize);
#endif
// Initialize first directory entry in order for copy to make use of it (it's typically updated by the DOS sys tool).
//
memset(pDirEntry->FileName, ' ', 8);
memset(pDirEntry->FileName, ' ', 3);
pDirEntry->FileName[0] = 0xe5; // Deleted file tag.
pDirEntry->FATTr = 0;
memset(pDirEntry->FOO, ' ', 10);
pDirEntry->LModTime = 0;
pDirEntry->LModDate = 0;
pDirEntry->FirstClust = 0;
pDirEntry->FileSize = 0;
// Write the updated boot sector back to disk.
//
if ((Status = WriteSector(pParams->DriveNum, Cylinder, Head, Sector, gTempSector)) != 0)
{
printf("ERROR: Unable to write root a directory sector (status=0x%x).\r\n", Status);
return(-1);
}
// Copy the bootloader image. It's assumed that the copy will be to a
// contiguous group of sectors. This might not be true if the disk
// already contains files (documented setup requirement) or if the disk
// contains bad sector(s).
//
// TODO - this area should be revisited.
//
sprintf(SystemCommand, "copy %s %c:", pParams->pLoaderFileName, pParams->DriveLetter);
SystemCommand[MAX_COMMAND_STRING - 1] = '\0';
if (system(SystemCommand) == -1)
{
printf("ERROR: Unable to transfer bootloader.\r\n");
return(-1);
}
return(0);
}
//
// Convert a LBA address to a physical CHS address that's used by the BIOS.
//
static void LBA2PCHS(unsigned long LBA, unsigned short *pCylinder, unsigned char *pHead, unsigned char *pSector, PBIOSPB pBPB)
{
unsigned short Temp = 0;
// Do the math...
*pCylinder = (unsigned short)(LBA / (pBPB->NumHeads * pBPB->SectsPerTrack));
Temp = (unsigned short)(LBA % (pBPB->NumHeads * pBPB->SectsPerTrack));
*pHead = (unsigned char)(Temp / pBPB->SectsPerTrack);
*pSector = (unsigned char)(Temp % pBPB->SectsPerTrack) + 1;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -